diff options
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 114 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 62 |
2 files changed, 111 insertions, 65 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 26fafb469..1ac0201b8 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -11,7 +11,10 @@ pub mod make; | |||
11 | use std::marker::PhantomData; | 11 | use std::marker::PhantomData; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken}, | 14 | syntax_node::{ |
15 | NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren, | ||
16 | SyntaxToken, | ||
17 | }, | ||
15 | SmolStr, SyntaxKind, | 18 | SmolStr, SyntaxKind, |
16 | }; | 19 | }; |
17 | 20 | ||
@@ -30,16 +33,24 @@ pub use self::{ | |||
30 | /// conversion itself has zero runtime cost: ast and syntax nodes have exactly | 33 | /// conversion itself has zero runtime cost: ast and syntax nodes have exactly |
31 | /// the same representation: a pointer to the tree root and a pointer to the | 34 | /// the same representation: a pointer to the tree root and a pointer to the |
32 | /// node itself. | 35 | /// node itself. |
33 | pub trait AstNode: std::fmt::Display { | 36 | pub trait AstNode: AstElement { |
34 | fn can_cast(kind: SyntaxKind) -> bool | 37 | fn can_cast(kind: SyntaxKind) -> bool |
35 | where | 38 | where |
36 | Self: Sized; | 39 | Self: Sized; |
37 | 40 | ||
38 | fn cast(syntax: SyntaxNode) -> Option<Self> | 41 | fn cast_or_return(syntax: SyntaxNode) -> Result<Self, SyntaxNode> |
39 | where | 42 | where |
40 | Self: Sized; | 43 | Self: Sized; |
41 | 44 | ||
45 | fn cast(syntax: SyntaxNode) -> Option<Self> | ||
46 | where | ||
47 | Self: Sized, | ||
48 | { | ||
49 | <Self as AstNode>::cast_or_return(syntax).ok() | ||
50 | } | ||
51 | |||
42 | fn syntax(&self) -> &SyntaxNode; | 52 | fn syntax(&self) -> &SyntaxNode; |
53 | fn into_syntax(self) -> SyntaxNode; | ||
43 | } | 54 | } |
44 | 55 | ||
45 | #[test] | 56 | #[test] |
@@ -48,16 +59,51 @@ fn assert_ast_is_object_safe() { | |||
48 | } | 59 | } |
49 | 60 | ||
50 | /// Like `AstNode`, but wraps tokens rather than interior nodes. | 61 | /// Like `AstNode`, but wraps tokens rather than interior nodes. |
51 | pub trait AstToken { | 62 | pub trait AstToken: AstElement { |
52 | fn cast(token: SyntaxToken) -> Option<Self> | 63 | fn can_cast(token: SyntaxKind) -> bool |
53 | where | 64 | where |
54 | Self: Sized; | 65 | Self: Sized; |
66 | |||
67 | fn cast_or_return(syntax: SyntaxToken) -> Result<Self, SyntaxToken> | ||
68 | where | ||
69 | Self: Sized; | ||
70 | |||
71 | fn cast(syntax: SyntaxToken) -> Option<Self> | ||
72 | where | ||
73 | Self: Sized, | ||
74 | { | ||
75 | <Self as AstToken>::cast_or_return(syntax).ok() | ||
76 | } | ||
77 | |||
55 | fn syntax(&self) -> &SyntaxToken; | 78 | fn syntax(&self) -> &SyntaxToken; |
79 | fn into_syntax(self) -> SyntaxToken; | ||
80 | |||
56 | fn text(&self) -> &SmolStr { | 81 | fn text(&self) -> &SmolStr { |
57 | self.syntax().text() | 82 | self.syntax().text() |
58 | } | 83 | } |
59 | } | 84 | } |
60 | 85 | ||
86 | /// Like `AstNode`, but wraps either nodes or tokens rather than interior nodes. | ||
87 | pub trait AstElement: std::fmt::Display { | ||
88 | fn can_cast_element(kind: SyntaxKind) -> bool | ||
89 | where | ||
90 | Self: Sized; | ||
91 | |||
92 | fn cast_or_return_element(syntax: SyntaxElement) -> Result<Self, SyntaxElement> | ||
93 | where | ||
94 | Self: Sized; | ||
95 | |||
96 | fn cast_element(syntax: SyntaxElement) -> Option<Self> | ||
97 | where | ||
98 | Self: Sized, | ||
99 | { | ||
100 | <Self as AstElement>::cast_or_return_element(syntax).ok() | ||
101 | } | ||
102 | |||
103 | fn syntax_element(&self) -> NodeOrToken<&SyntaxNode, &SyntaxToken>; | ||
104 | fn into_syntax_element(self) -> SyntaxElement; | ||
105 | } | ||
106 | |||
61 | /// An iterator over `SyntaxNode` children of a particular AST type. | 107 | /// An iterator over `SyntaxNode` children of a particular AST type. |
62 | #[derive(Debug, Clone)] | 108 | #[derive(Debug, Clone)] |
63 | pub struct AstChildren<N> { | 109 | pub struct AstChildren<N> { |
@@ -86,6 +132,64 @@ fn children<P: AstNode + ?Sized, C: AstNode>(parent: &P) -> AstChildren<C> { | |||
86 | AstChildren::new(parent.syntax()) | 132 | AstChildren::new(parent.syntax()) |
87 | } | 133 | } |
88 | 134 | ||
135 | /// An iterator over `SyntaxToken` children of a particular AST type. | ||
136 | #[derive(Debug, Clone)] | ||
137 | pub struct AstChildTokens<N> { | ||
138 | inner: SyntaxElementChildren, | ||
139 | ph: PhantomData<N>, | ||
140 | } | ||
141 | |||
142 | impl<N> AstChildTokens<N> { | ||
143 | fn new(parent: &SyntaxNode) -> Self { | ||
144 | AstChildTokens { inner: parent.children_with_tokens(), ph: PhantomData } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl<N: AstToken> Iterator for AstChildTokens<N> { | ||
149 | type Item = N; | ||
150 | fn next(&mut self) -> Option<N> { | ||
151 | self.inner.by_ref().filter_map(|x| x.into_token()).find_map(N::cast) | ||
152 | } | ||
153 | } | ||
154 | |||
155 | fn child_token_opt<P: AstNode + ?Sized, C: AstToken>(parent: &P) -> Option<C> { | ||
156 | child_tokens(parent).next() | ||
157 | } | ||
158 | |||
159 | fn child_tokens<P: AstNode + ?Sized, C: AstToken>(parent: &P) -> AstChildTokens<C> { | ||
160 | AstChildTokens::new(parent.syntax()) | ||
161 | } | ||
162 | |||
163 | /// An iterator over `SyntaxNode` children of a particular AST type. | ||
164 | #[derive(Debug, Clone)] | ||
165 | pub struct AstChildElements<N> { | ||
166 | inner: SyntaxElementChildren, | ||
167 | ph: PhantomData<N>, | ||
168 | } | ||
169 | |||
170 | impl<N> AstChildElements<N> { | ||
171 | fn new(parent: &SyntaxNode) -> Self { | ||
172 | AstChildElements { inner: parent.children_with_tokens(), ph: PhantomData } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | impl<N: AstElement> Iterator for AstChildElements<N> { | ||
177 | type Item = N; | ||
178 | fn next(&mut self) -> Option<N> { | ||
179 | self.inner.by_ref().find_map(N::cast_element) | ||
180 | } | ||
181 | } | ||
182 | |||
183 | #[allow(dead_code)] | ||
184 | fn child_element_opt<P: AstNode + ?Sized, C: AstElement>(parent: &P) -> Option<C> { | ||
185 | child_elements(parent).next() | ||
186 | } | ||
187 | |||
188 | #[allow(dead_code)] | ||
189 | fn child_elements<P: AstNode + ?Sized, C: AstElement>(parent: &P) -> AstChildElements<C> { | ||
190 | AstChildElements::new(parent.syntax()) | ||
191 | } | ||
192 | |||
89 | #[test] | 193 | #[test] |
90 | fn test_doc_comment_none() { | 194 | fn test_doc_comment_none() { |
91 | let file = SourceFile::parse( | 195 | let file = SourceFile::parse( |
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs index 1a51b8d3b..e8320b57e 100644 --- a/crates/ra_syntax/src/ast/tokens.rs +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -1,26 +1,10 @@ | |||
1 | //! There are many AstNodes, but only a few tokens, so we hand-write them here. | 1 | //! There are many AstNodes, but only a few tokens, so we hand-write them here. |
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | ast::AstToken, | 4 | ast::{AstToken, Comment, RawString, String, Whitespace}, |
5 | SyntaxKind::{COMMENT, RAW_STRING, STRING, WHITESPACE}, | 5 | TextRange, TextUnit, |
6 | SyntaxToken, TextRange, TextUnit, | ||
7 | }; | 6 | }; |
8 | 7 | ||
9 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
10 | pub struct Comment(SyntaxToken); | ||
11 | |||
12 | impl AstToken for Comment { | ||
13 | fn cast(token: SyntaxToken) -> Option<Self> { | ||
14 | match token.kind() { | ||
15 | COMMENT => Some(Comment(token)), | ||
16 | _ => None, | ||
17 | } | ||
18 | } | ||
19 | fn syntax(&self) -> &SyntaxToken { | ||
20 | &self.0 | ||
21 | } | ||
22 | } | ||
23 | |||
24 | impl Comment { | 8 | impl Comment { |
25 | pub fn kind(&self) -> CommentKind { | 9 | pub fn kind(&self) -> CommentKind { |
26 | kind_by_prefix(self.text()) | 10 | kind_by_prefix(self.text()) |
@@ -89,20 +73,6 @@ fn prefix_by_kind(kind: CommentKind) -> &'static str { | |||
89 | unreachable!() | 73 | unreachable!() |
90 | } | 74 | } |
91 | 75 | ||
92 | pub struct Whitespace(SyntaxToken); | ||
93 | |||
94 | impl AstToken for Whitespace { | ||
95 | fn cast(token: SyntaxToken) -> Option<Self> { | ||
96 | match token.kind() { | ||
97 | WHITESPACE => Some(Whitespace(token)), | ||
98 | _ => None, | ||
99 | } | ||
100 | } | ||
101 | fn syntax(&self) -> &SyntaxToken { | ||
102 | &self.0 | ||
103 | } | ||
104 | } | ||
105 | |||
106 | impl Whitespace { | 76 | impl Whitespace { |
107 | pub fn spans_multiple_lines(&self) -> bool { | 77 | pub fn spans_multiple_lines(&self) -> bool { |
108 | let text = self.text(); | 78 | let text = self.text(); |
@@ -168,20 +138,6 @@ pub trait HasStringValue: HasQuotes { | |||
168 | fn value(&self) -> Option<std::string::String>; | 138 | fn value(&self) -> Option<std::string::String>; |
169 | } | 139 | } |
170 | 140 | ||
171 | pub struct String(SyntaxToken); | ||
172 | |||
173 | impl AstToken for String { | ||
174 | fn cast(token: SyntaxToken) -> Option<Self> { | ||
175 | match token.kind() { | ||
176 | STRING => Some(String(token)), | ||
177 | _ => None, | ||
178 | } | ||
179 | } | ||
180 | fn syntax(&self) -> &SyntaxToken { | ||
181 | &self.0 | ||
182 | } | ||
183 | } | ||
184 | |||
185 | impl HasStringValue for String { | 141 | impl HasStringValue for String { |
186 | fn value(&self) -> Option<std::string::String> { | 142 | fn value(&self) -> Option<std::string::String> { |
187 | let text = self.text().as_str(); | 143 | let text = self.text().as_str(); |
@@ -201,20 +157,6 @@ impl HasStringValue for String { | |||
201 | } | 157 | } |
202 | } | 158 | } |
203 | 159 | ||
204 | pub struct RawString(SyntaxToken); | ||
205 | |||
206 | impl AstToken for RawString { | ||
207 | fn cast(token: SyntaxToken) -> Option<Self> { | ||
208 | match token.kind() { | ||
209 | RAW_STRING => Some(RawString(token)), | ||
210 | _ => None, | ||
211 | } | ||
212 | } | ||
213 | fn syntax(&self) -> &SyntaxToken { | ||
214 | &self.0 | ||
215 | } | ||
216 | } | ||
217 | |||
218 | impl HasStringValue for RawString { | 160 | impl HasStringValue for RawString { |
219 | fn value(&self) -> Option<std::string::String> { | 161 | fn value(&self) -> Option<std::string::String> { |
220 | let text = self.text().as_str(); | 162 | let text = self.text().as_str(); |