diff options
Diffstat (limited to 'crates/ra_syntax/src/algo')
-rw-r--r-- | crates/ra_syntax/src/algo/mod.rs | 54 | ||||
-rw-r--r-- | crates/ra_syntax/src/algo/visit.rs | 63 | ||||
-rw-r--r-- | crates/ra_syntax/src/algo/walk.rs | 6 |
3 files changed, 71 insertions, 52 deletions
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs index e686a5704..b4896c482 100644 --- a/crates/ra_syntax/src/algo/mod.rs +++ b/crates/ra_syntax/src/algo/mod.rs | |||
@@ -1,16 +1,18 @@ | |||
1 | pub mod walk; | ||
2 | pub mod visit; | 1 | pub mod visit; |
2 | pub mod walk; | ||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | SyntaxNodeRef, TextUnit, TextRange, | ||
6 | text_utils::{contains_offset_nonstrict, is_subrange}, | 5 | text_utils::{contains_offset_nonstrict, is_subrange}, |
6 | SyntaxNodeRef, TextRange, TextUnit, | ||
7 | }; | 7 | }; |
8 | 8 | ||
9 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { | 9 | pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffset { |
10 | let range = node.range(); | 10 | let range = node.range(); |
11 | assert!( | 11 | assert!( |
12 | contains_offset_nonstrict(range, offset), | 12 | contains_offset_nonstrict(range, offset), |
13 | "Bad offset: range {:?} offset {:?}", range, offset | 13 | "Bad offset: range {:?} offset {:?}", |
14 | range, | ||
15 | offset | ||
14 | ); | 16 | ); |
15 | if range.is_empty() { | 17 | if range.is_empty() { |
16 | return LeafAtOffset::None; | 18 | return LeafAtOffset::None; |
@@ -20,20 +22,23 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse | |||
20 | return LeafAtOffset::Single(node); | 22 | return LeafAtOffset::Single(node); |
21 | } | 23 | } |
22 | 24 | ||
23 | let mut children = node.children() | 25 | let mut children = node.children().filter(|child| { |
24 | .filter(|child| { | 26 | let child_range = child.range(); |
25 | let child_range = child.range(); | 27 | !child_range.is_empty() && contains_offset_nonstrict(child_range, offset) |
26 | !child_range.is_empty() && contains_offset_nonstrict(child_range, offset) | 28 | }); |
27 | }); | ||
28 | 29 | ||
29 | let left = children.next().unwrap(); | 30 | let left = children.next().unwrap(); |
30 | let right = children.next(); | 31 | let right = children.next(); |
31 | assert!(children.next().is_none()); | 32 | assert!(children.next().is_none()); |
32 | return if let Some(right) = right { | 33 | return if let Some(right) = right { |
33 | match (find_leaf_at_offset(left, offset), find_leaf_at_offset(right, offset)) { | 34 | match ( |
34 | (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => | 35 | find_leaf_at_offset(left, offset), |
35 | LeafAtOffset::Between(left, right), | 36 | find_leaf_at_offset(right, offset), |
36 | _ => unreachable!() | 37 | ) { |
38 | (LeafAtOffset::Single(left), LeafAtOffset::Single(right)) => { | ||
39 | LeafAtOffset::Between(left, right) | ||
40 | } | ||
41 | _ => unreachable!(), | ||
37 | } | 42 | } |
38 | } else { | 43 | } else { |
39 | find_leaf_at_offset(left, offset) | 44 | find_leaf_at_offset(left, offset) |
@@ -44,7 +49,7 @@ pub fn find_leaf_at_offset(node: SyntaxNodeRef, offset: TextUnit) -> LeafAtOffse | |||
44 | pub enum LeafAtOffset<'a> { | 49 | pub enum LeafAtOffset<'a> { |
45 | None, | 50 | None, |
46 | Single(SyntaxNodeRef<'a>), | 51 | Single(SyntaxNodeRef<'a>), |
47 | Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>) | 52 | Between(SyntaxNodeRef<'a>, SyntaxNodeRef<'a>), |
48 | } | 53 | } |
49 | 54 | ||
50 | impl<'a> LeafAtOffset<'a> { | 55 | impl<'a> LeafAtOffset<'a> { |
@@ -52,7 +57,7 @@ impl<'a> LeafAtOffset<'a> { | |||
52 | match self { | 57 | match self { |
53 | LeafAtOffset::None => None, | 58 | LeafAtOffset::None => None, |
54 | LeafAtOffset::Single(node) => Some(node), | 59 | LeafAtOffset::Single(node) => Some(node), |
55 | LeafAtOffset::Between(_, right) => Some(right) | 60 | LeafAtOffset::Between(_, right) => Some(right), |
56 | } | 61 | } |
57 | } | 62 | } |
58 | 63 | ||
@@ -60,7 +65,7 @@ impl<'a> LeafAtOffset<'a> { | |||
60 | match self { | 65 | match self { |
61 | LeafAtOffset::None => None, | 66 | LeafAtOffset::None => None, |
62 | LeafAtOffset::Single(node) => Some(node), | 67 | LeafAtOffset::Single(node) => Some(node), |
63 | LeafAtOffset::Between(left, _) => Some(left) | 68 | LeafAtOffset::Between(left, _) => Some(left), |
64 | } | 69 | } |
65 | } | 70 | } |
66 | } | 71 | } |
@@ -71,8 +76,14 @@ impl<'f> Iterator for LeafAtOffset<'f> { | |||
71 | fn next(&mut self) -> Option<SyntaxNodeRef<'f>> { | 76 | fn next(&mut self) -> Option<SyntaxNodeRef<'f>> { |
72 | match *self { | 77 | match *self { |
73 | LeafAtOffset::None => None, | 78 | LeafAtOffset::None => None, |
74 | LeafAtOffset::Single(node) => { *self = LeafAtOffset::None; Some(node) } | 79 | LeafAtOffset::Single(node) => { |
75 | LeafAtOffset::Between(left, right) => { *self = LeafAtOffset::Single(right); Some(left) } | 80 | *self = LeafAtOffset::None; |
81 | Some(node) | ||
82 | } | ||
83 | LeafAtOffset::Between(left, right) => { | ||
84 | *self = LeafAtOffset::Single(right); | ||
85 | Some(left) | ||
86 | } | ||
76 | } | 87 | } |
77 | } | 88 | } |
78 | } | 89 | } |
@@ -81,14 +92,15 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe | |||
81 | assert!( | 92 | assert!( |
82 | is_subrange(root.range(), range), | 93 | is_subrange(root.range(), range), |
83 | "node range: {:?}, target range: {:?}", | 94 | "node range: {:?}, target range: {:?}", |
84 | root.range(), range, | 95 | root.range(), |
96 | range, | ||
85 | ); | 97 | ); |
86 | let (left, right) = match ( | 98 | let (left, right) = match ( |
87 | find_leaf_at_offset(root, range.start()).right_biased(), | 99 | find_leaf_at_offset(root, range.start()).right_biased(), |
88 | find_leaf_at_offset(root, range.end()).left_biased() | 100 | find_leaf_at_offset(root, range.end()).left_biased(), |
89 | ) { | 101 | ) { |
90 | (Some(l), Some(r)) => (l, r), | 102 | (Some(l), Some(r)) => (l, r), |
91 | _ => return root | 103 | _ => return root, |
92 | }; | 104 | }; |
93 | 105 | ||
94 | common_ancestor(left, right) | 106 | common_ancestor(left, right) |
@@ -103,7 +115,7 @@ fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNo | |||
103 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) | 115 | panic!("Can't find common ancestor of {:?} and {:?}", n1, n2) |
104 | } | 116 | } |
105 | 117 | ||
106 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item=T> { | 118 | pub fn generate<T>(seed: Option<T>, step: impl Fn(&T) -> Option<T>) -> impl Iterator<Item = T> { |
107 | ::itertools::unfold(seed, move |slot| { | 119 | ::itertools::unfold(seed, move |slot| { |
108 | slot.take().map(|curr| { | 120 | slot.take().map(|curr| { |
109 | *slot = step(&curr); | 121 | *slot = step(&curr); |
diff --git a/crates/ra_syntax/src/algo/visit.rs b/crates/ra_syntax/src/algo/visit.rs index 1ae988a87..c021f464c 100644 --- a/crates/ra_syntax/src/algo/visit.rs +++ b/crates/ra_syntax/src/algo/visit.rs | |||
@@ -1,23 +1,31 @@ | |||
1 | use std::marker::PhantomData; | 1 | use crate::{AstNode, SyntaxNodeRef}; |
2 | use crate::{SyntaxNodeRef, AstNode}; | ||
3 | 2 | ||
3 | use std::marker::PhantomData; | ||
4 | 4 | ||
5 | pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { | 5 | 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> { | 9 | pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> { |
10 | EmptyVisitorCtx { ph: PhantomData, ctx } | 10 | EmptyVisitorCtx { |
11 | ph: PhantomData, | ||
12 | ctx, | ||
13 | } | ||
11 | } | 14 | } |
12 | 15 | ||
13 | pub trait Visitor<'a>: Sized { | 16 | pub trait Visitor<'a>: Sized { |
14 | type Output; | 17 | type Output; |
15 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; | 18 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; |
16 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> | 19 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> |
17 | where N: AstNode<'a>, | 20 | where |
18 | F: FnOnce(N) -> Self::Output, | 21 | N: AstNode<'a>, |
22 | F: FnOnce(N) -> Self::Output, | ||
19 | { | 23 | { |
20 | Vis { inner: self, f, ph: PhantomData } | 24 | Vis { |
25 | inner: self, | ||
26 | f, | ||
27 | ph: PhantomData, | ||
28 | } | ||
21 | } | 29 | } |
22 | } | 30 | } |
23 | 31 | ||
@@ -26,16 +34,21 @@ pub trait VisitorCtx<'a>: Sized { | |||
26 | type Ctx; | 34 | type Ctx; |
27 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>; | 35 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx>; |
28 | fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F> | 36 | fn visit<N, F>(self, f: F) -> VisCtx<Self, N, F> |
29 | where N: AstNode<'a>, | 37 | where |
30 | F: FnOnce(N, Self::Ctx) -> Self::Output, | 38 | N: AstNode<'a>, |
39 | F: FnOnce(N, Self::Ctx) -> Self::Output, | ||
31 | { | 40 | { |
32 | VisCtx { inner: self, f, ph: PhantomData } | 41 | VisCtx { |
42 | inner: self, | ||
43 | f, | ||
44 | ph: PhantomData, | ||
45 | } | ||
33 | } | 46 | } |
34 | } | 47 | } |
35 | 48 | ||
36 | #[derive(Debug)] | 49 | #[derive(Debug)] |
37 | struct EmptyVisitor<T> { | 50 | struct EmptyVisitor<T> { |
38 | ph: PhantomData<fn() -> T> | 51 | ph: PhantomData<fn() -> T>, |
39 | } | 52 | } |
40 | 53 | ||
41 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { | 54 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { |
@@ -69,10 +82,10 @@ pub struct Vis<V, N, F> { | |||
69 | } | 82 | } |
70 | 83 | ||
71 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> | 84 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> |
72 | where | 85 | where |
73 | V: Visitor<'a>, | 86 | V: Visitor<'a>, |
74 | N: AstNode<'a>, | 87 | N: AstNode<'a>, |
75 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, | 88 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, |
76 | { | 89 | { |
77 | type Output = <V as Visitor<'a>>::Output; | 90 | type Output = <V as Visitor<'a>>::Output; |
78 | 91 | ||
@@ -90,21 +103,19 @@ pub struct VisCtx<V, N, F> { | |||
90 | } | 103 | } |
91 | 104 | ||
92 | impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> | 105 | impl<'a, V, N, F> VisitorCtx<'a> for VisCtx<V, N, F> |
93 | where | 106 | where |
94 | V: VisitorCtx<'a>, | 107 | V: VisitorCtx<'a>, |
95 | N: AstNode<'a>, | 108 | N: AstNode<'a>, |
96 | F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output, | 109 | F: FnOnce(N, <V as VisitorCtx<'a>>::Ctx) -> <V as VisitorCtx<'a>>::Output, |
97 | { | 110 | { |
98 | type Output = <V as VisitorCtx<'a>>::Output; | 111 | type Output = <V as VisitorCtx<'a>>::Output; |
99 | type Ctx = <V as VisitorCtx<'a>>::Ctx; | 112 | type Ctx = <V as VisitorCtx<'a>>::Ctx; |
100 | 113 | ||
101 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> { | 114 | fn accept(self, node: SyntaxNodeRef<'a>) -> Result<Self::Output, Self::Ctx> { |
102 | let VisCtx { inner, f, .. } = self; | 115 | let VisCtx { inner, f, .. } = self; |
103 | inner.accept(node).or_else(|ctx| | 116 | inner.accept(node).or_else(|ctx| match N::cast(node) { |
104 | match N::cast(node) { | 117 | None => Err(ctx), |
105 | None => Err(ctx), | 118 | Some(node) => Ok(f(node, ctx)), |
106 | Some(node) => Ok(f(node, ctx)) | 119 | }) |
107 | } | ||
108 | ) | ||
109 | } | 120 | } |
110 | } | 121 | } |
diff --git a/crates/ra_syntax/src/algo/walk.rs b/crates/ra_syntax/src/algo/walk.rs index d34415626..9afa86401 100644 --- a/crates/ra_syntax/src/algo/walk.rs +++ b/crates/ra_syntax/src/algo/walk.rs | |||
@@ -1,8 +1,4 @@ | |||
1 | use crate::{ | 1 | use crate::{algo::generate, SyntaxNodeRef}; |
2 | SyntaxNodeRef, | ||
3 | algo::generate, | ||
4 | }; | ||
5 | |||
6 | 2 | ||
7 | #[derive(Debug, Copy, Clone)] | 3 | #[derive(Debug, Copy, Clone)] |
8 | pub enum WalkEvent<'a> { | 4 | pub enum WalkEvent<'a> { |