diff options
author | Luca Barbieri <[email protected]> | 2020-04-03 20:12:08 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-04-08 16:15:12 +0100 |
commit | 68196ccc10c60de52bb771d295879456f73ede95 (patch) | |
tree | cec60917f9c4475c49d4842c05469f19ad2bff86 /crates/ra_syntax/src/ast.rs | |
parent | 4762c6d9c66dc1b6be9b9010dbe787ef8d69530a (diff) |
Add AstElement trait, generate tokens, support tokens in enums
- Adds a new AstElement trait that is implemented by all generated
node, token and enum structs
- Overhauls the code generators to code-generate all tokens, and
also enhances enums to support including tokens, node, and nested
enums
Diffstat (limited to 'crates/ra_syntax/src/ast.rs')
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 114 |
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; | |||
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( |