Skip to content

Commit fb9b516

Browse files
committed
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
1 parent 15a7b5d commit fb9b516

File tree

4 files changed

+10018
-698
lines changed

4 files changed

+10018
-698
lines changed

crates/ra_syntax/src/ast.rs

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ pub mod make;
1111
use std::marker::PhantomData;
1212

1313
use crate::{
14-
syntax_node::{SyntaxNode, SyntaxNodeChildren, SyntaxToken},
14+
syntax_node::{
15+
NodeOrToken, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren,
16+
SyntaxToken,
17+
},
1518
SmolStr, SyntaxKind,
1619
};
1720

@@ -30,16 +33,24 @@ pub use self::{
3033
/// conversion itself has zero runtime cost: ast and syntax nodes have exactly
3134
/// the same representation: a pointer to the tree root and a pointer to the
3235
/// node itself.
33-
pub trait AstNode: std::fmt::Display {
36+
pub trait AstNode: AstElement {
3437
fn can_cast(kind: SyntaxKind) -> bool
3538
where
3639
Self: Sized;
3740

38-
fn cast(syntax: SyntaxNode) -> Option<Self>
41+
fn cast_or_return(syntax: SyntaxNode) -> Result<Self, SyntaxNode>
3942
where
4043
Self: Sized;
4144

45+
fn cast(syntax: SyntaxNode) -> Option<Self>
46+
where
47+
Self: Sized,
48+
{
49+
<Self as AstNode>::cast_or_return(syntax).ok()
50+
}
51+
4252
fn syntax(&self) -> &SyntaxNode;
53+
fn into_syntax(self) -> SyntaxNode;
4354
}
4455

4556
#[test]
@@ -48,16 +59,51 @@ fn assert_ast_is_object_safe() {
4859
}
4960

5061
/// 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
5364
where
5465
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+
5578
fn syntax(&self) -> &SyntaxToken;
79+
fn into_syntax(self) -> SyntaxToken;
80+
5681
fn text(&self) -> &SmolStr {
5782
self.syntax().text()
5883
}
5984
}
6085

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+
61107
/// An iterator over `SyntaxNode` children of a particular AST type.
62108
#[derive(Debug, Clone)]
63109
pub struct AstChildren<N> {
@@ -86,6 +132,64 @@ fn children<P: AstNode + ?Sized, C: AstNode>(parent: &P) -> AstChildren<C> {
86132
AstChildren::new(parent.syntax())
87133
}
88134

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+
89193
#[test]
90194
fn test_doc_comment_none() {
91195
let file = SourceFile::parse(

0 commit comments

Comments
 (0)