@@ -11,7 +11,10 @@ pub mod make;
11
11
use std:: marker:: PhantomData ;
12
12
13
13
use crate :: {
14
- syntax_node:: { SyntaxNode , SyntaxNodeChildren , SyntaxToken } ,
14
+ syntax_node:: {
15
+ NodeOrToken , SyntaxElement , SyntaxElementChildren , SyntaxNode , SyntaxNodeChildren ,
16
+ SyntaxToken ,
17
+ } ,
15
18
SmolStr , SyntaxKind ,
16
19
} ;
17
20
@@ -30,16 +33,24 @@ pub use self::{
30
33
/// conversion itself has zero runtime cost: ast and syntax nodes have exactly
31
34
/// the same representation: a pointer to the tree root and a pointer to the
32
35
/// node itself.
33
- pub trait AstNode : std :: fmt :: Display {
36
+ pub trait AstNode : AstElement {
34
37
fn can_cast ( kind : SyntaxKind ) -> bool
35
38
where
36
39
Self : Sized ;
37
40
38
- fn cast ( syntax : SyntaxNode ) -> Option < Self >
41
+ fn cast_or_return ( syntax : SyntaxNode ) -> Result < Self , SyntaxNode >
39
42
where
40
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
52
fn syntax ( & self ) -> & SyntaxNode ;
53
+ fn into_syntax ( self ) -> SyntaxNode ;
43
54
}
44
55
45
56
#[ test]
@@ -48,16 +59,51 @@ fn assert_ast_is_object_safe() {
48
59
}
49
60
50
61
/// Like `AstNode`, but wraps tokens rather than interior nodes.
51
- pub trait AstToken {
52
- fn cast ( token : SyntaxToken ) -> Option < Self >
62
+ pub trait AstToken : AstElement {
63
+ fn can_cast ( token : SyntaxKind ) -> bool
53
64
where
54
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
78
fn syntax ( & self ) -> & SyntaxToken ;
79
+ fn into_syntax ( self ) -> SyntaxToken ;
80
+
56
81
fn text ( & self ) -> & SmolStr {
57
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
107
/// An iterator over `SyntaxNode` children of a particular AST type.
62
108
#[ derive( Debug , Clone ) ]
63
109
pub struct AstChildren < N > {
@@ -86,6 +132,64 @@ fn children<P: AstNode + ?Sized, C: AstNode>(parent: &P) -> AstChildren<C> {
86
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
193
#[ test]
90
194
fn test_doc_comment_none ( ) {
91
195
let file = SourceFile :: parse (
0 commit comments