diff options
Diffstat (limited to 'crates/libsyntax2/src/algo')
-rw-r--r-- | crates/libsyntax2/src/algo/visit.rs | 58 | ||||
-rw-r--r-- | crates/libsyntax2/src/algo/walk.rs | 10 |
2 files changed, 63 insertions, 5 deletions
diff --git a/crates/libsyntax2/src/algo/visit.rs b/crates/libsyntax2/src/algo/visit.rs index a36c8f45e..9f1c127c7 100644 --- a/crates/libsyntax2/src/algo/visit.rs +++ b/crates/libsyntax2/src/algo/visit.rs | |||
@@ -6,6 +6,10 @@ pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { | |||
6 | EmptyVisitor { ph: PhantomData } | 6 | EmptyVisitor { ph: PhantomData } |
7 | } | 7 | } |
8 | 8 | ||
9 | pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output=T, Ctx=C> { | ||
10 | EmptyVisitorCtx { ph: PhantomData, ctx } | ||
11 | } | ||
12 | |||
9 | pub trait Visitor<'a>: Sized { | 13 | pub trait Visitor<'a>: Sized { |
10 | type Output; | 14 | type Output; |
11 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; | 15 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; |
@@ -17,6 +21,18 @@ pub trait Visitor<'a>: Sized { | |||
17 | } | 21 | } |
18 | } | 22 | } |
19 | 23 | ||
24 | pub trait VisitorCtx<'a>: Sized { | ||
25 | type Output; | ||
26 | type Ctx; | ||
27 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>; | ||
28 | fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F> | ||
29 | where N: AstNode<'a>, | ||
30 | F: FnOnce(N, Self::Ctx) -> Self::Output, | ||
31 | { | ||
32 | VisCtx { inner: self, f, ph: PhantomData } | ||
33 | } | ||
34 | } | ||
35 | |||
20 | #[derive(Debug)] | 36 | #[derive(Debug)] |
21 | struct EmptyVisitor<T> { | 37 | struct EmptyVisitor<T> { |
22 | ph: PhantomData<fn() -> T> | 38 | ph: PhantomData<fn() -> T> |
@@ -31,6 +47,21 @@ impl<'a, T> Visitor<'a> for EmptyVisitor<T> { | |||
31 | } | 47 | } |
32 | 48 | ||
33 | #[derive(Debug)] | 49 | #[derive(Debug)] |
50 | struct EmptyVisitorCtx<T, C> { | ||
51 | ctx: C, | ||
52 | ph: PhantomData<fn() -> T>, | ||
53 | } | ||
54 | |||
55 | impl<'a, T, C> VisitorCtx<'a> for EmptyVisitorCtx<T, C> { | ||
56 | type Output = T; | ||
57 | type Ctx = C; | ||
58 | |||
59 | fn accept(self, _node: SyntaxNodeRef<'a>) -> Result<T, C> { | ||
60 | Err(self.ctx) | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #[derive(Debug)] | ||
34 | pub struct Vis<V, N, F> { | 65 | pub struct Vis<V, N, F> { |
35 | inner: V, | 66 | inner: V, |
36 | f: F, | 67 | f: F, |
@@ -50,3 +81,30 @@ impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> | |||
50 | inner.accept(node).or_else(|| N::cast(node).map(f)) | 81 | inner.accept(node).or_else(|| N::cast(node).map(f)) |
51 | } | 82 | } |
52 | } | 83 | } |
84 | |||
85 | #[derive(Debug)] | ||
86 | pub struct VisCtx<V, N, F> { | ||
87 | inner: V, | ||
88 | f: F, | ||
89 | ph: PhantomData<fn(N)>, | ||
90 | } | ||
91 | |||
92 | impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> | ||
93 | where | ||
94 | V: VisitorCtx<'a>, | ||
95 | N: AstNode<'a>, | ||
96 | F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output, | ||
97 | { | ||
98 | type Output = <V as VisitorCtx<'a>>::Output; | ||
99 | type Ctx = <V as VisitorCtx<'a>>::Ctx; | ||
100 | |||
101 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> { | ||
102 | let VisCtx { inner, f, .. } = self; | ||
103 | inner.accept(node).or_else(|ctx| | ||
104 | match N::cast(node) { | ||
105 | None => Err(ctx), | ||
106 | Some(node) => Ok(f(node, ctx)) | ||
107 | } | ||
108 | ) | ||
109 | } | ||
110 | } | ||
diff --git a/crates/libsyntax2/src/algo/walk.rs b/crates/libsyntax2/src/algo/walk.rs index d8797c453..536ee705f 100644 --- a/crates/libsyntax2/src/algo/walk.rs +++ b/crates/libsyntax2/src/algo/walk.rs | |||
@@ -17,19 +17,19 @@ pub enum WalkEvent<'a> { | |||
17 | } | 17 | } |
18 | 18 | ||
19 | pub fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = WalkEvent<'a>> { | 19 | pub fn walk<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator<Item = WalkEvent<'a>> { |
20 | generate(Some(WalkEvent::Enter(root)), |pos| { | 20 | generate(Some(WalkEvent::Enter(root)), move |pos| { |
21 | let next = match *pos { | 21 | let next = match *pos { |
22 | WalkEvent::Enter(node) => match node.first_child() { | 22 | WalkEvent::Enter(node) => match node.first_child() { |
23 | Some(child) => WalkEvent::Enter(child), | 23 | Some(child) => WalkEvent::Enter(child), |
24 | None => WalkEvent::Exit(node), | 24 | None => WalkEvent::Exit(node), |
25 | }, | 25 | }, |
26 | WalkEvent::Exit(node) => { | 26 | WalkEvent::Exit(node) => { |
27 | if node == root { | ||
28 | return None; | ||
29 | } | ||
27 | match node.next_sibling() { | 30 | match node.next_sibling() { |
28 | Some(sibling) => WalkEvent::Enter(sibling), | 31 | Some(sibling) => WalkEvent::Enter(sibling), |
29 | None => match node.parent() { | 32 | None => WalkEvent::Exit(node.parent().unwrap()), |
30 | Some(node) => WalkEvent::Exit(node), | ||
31 | None => return None, | ||
32 | }, | ||
33 | } | 33 | } |
34 | } | 34 | } |
35 | }; | 35 | }; |