aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast.rs')
-rw-r--r--crates/ra_syntax/src/ast.rs114
1 files changed, 109 insertions, 5 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(