aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast.rs114
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs62
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;
11use std::marker::PhantomData; 11use std::marker::PhantomData;
12 12
13use crate::{ 13use 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.
33pub trait AstNode: std::fmt::Display { 36pub 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.
51pub trait AstToken { 62pub 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.
87pub 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)]
63pub struct AstChildren<N> { 109pub 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)]
137pub struct AstChildTokens<N> {
138 inner: SyntaxElementChildren,
139 ph: PhantomData<N>,
140}
141
142impl<N> AstChildTokens<N> {
143 fn new(parent: &SyntaxNode) -> Self {
144 AstChildTokens { inner: parent.children_with_tokens(), ph: PhantomData }
145 }
146}
147
148impl<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
155fn child_token_opt<P: AstNode + ?Sized, C: AstToken>(parent: &P) -> Option<C> {
156 child_tokens(parent).next()
157}
158
159fn 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)]
165pub struct AstChildElements<N> {
166 inner: SyntaxElementChildren,
167 ph: PhantomData<N>,
168}
169
170impl<N> AstChildElements<N> {
171 fn new(parent: &SyntaxNode) -> Self {
172 AstChildElements { inner: parent.children_with_tokens(), ph: PhantomData }
173 }
174}
175
176impl<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)]
184fn child_element_opt<P: AstNode + ?Sized, C: AstElement>(parent: &P) -> Option<C> {
185 child_elements(parent).next()
186}
187
188#[allow(dead_code)]
189fn child_elements<P: AstNode + ?Sized, C: AstElement>(parent: &P) -> AstChildElements<C> {
190 AstChildElements::new(parent.syntax())
191}
192
89#[test] 193#[test]
90fn test_doc_comment_none() { 194fn 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
3use crate::{ 3use 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)]
10pub struct Comment(SyntaxToken);
11
12impl 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
24impl Comment { 8impl 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
92pub struct Whitespace(SyntaxToken);
93
94impl 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
106impl Whitespace { 76impl 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
171pub struct String(SyntaxToken);
172
173impl 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
185impl HasStringValue for String { 141impl 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
204pub struct RawString(SyntaxToken);
205
206impl 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
218impl HasStringValue for RawString { 160impl 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();