diff options
Diffstat (limited to 'crates/ra_syntax/src/ast/mod.rs')
-rw-r--r-- | crates/ra_syntax/src/ast/mod.rs | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast/mod.rs new file mode 100644 index 000000000..a6da82957 --- /dev/null +++ b/crates/ra_syntax/src/ast/mod.rs | |||
@@ -0,0 +1,206 @@ | |||
1 | mod generated; | ||
2 | |||
3 | use std::marker::PhantomData; | ||
4 | |||
5 | use itertools::Itertools; | ||
6 | use smol_str::SmolStr; | ||
7 | |||
8 | use { | ||
9 | SyntaxNodeRef, SyntaxKind::*, | ||
10 | yellow::{RefRoot, SyntaxNodeChildren}, | ||
11 | }; | ||
12 | pub use self::generated::*; | ||
13 | |||
14 | pub trait AstNode<'a>: Clone + Copy + 'a { | ||
15 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> | ||
16 | where Self: Sized; | ||
17 | fn syntax(self) -> SyntaxNodeRef<'a>; | ||
18 | } | ||
19 | |||
20 | pub trait NameOwner<'a>: AstNode<'a> { | ||
21 | fn name(self) -> Option<Name<'a>> { | ||
22 | child_opt(self) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | pub trait LoopBodyOwner<'a>: AstNode<'a> { | ||
27 | fn loop_body(self) -> Option<Block<'a>> { | ||
28 | child_opt(self) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub trait ArgListOwner<'a>: AstNode<'a> { | ||
33 | fn arg_list(self) -> Option<ArgList<'a>> { | ||
34 | child_opt(self) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | pub trait FnDefOwner<'a>: AstNode<'a> { | ||
39 | fn functions(self) -> AstChildren<'a, FnDef<'a>> { | ||
40 | children(self) | ||
41 | } | ||
42 | } | ||
43 | |||
44 | pub trait ModuleItemOwner<'a>: AstNode<'a> { | ||
45 | fn items(self) -> AstChildren<'a, ModuleItem<'a>> { | ||
46 | children(self) | ||
47 | } | ||
48 | } | ||
49 | |||
50 | pub trait TypeParamsOwner<'a>: AstNode<'a> { | ||
51 | fn type_param_list(self) -> Option<TypeParamList<'a>> { | ||
52 | child_opt(self) | ||
53 | } | ||
54 | |||
55 | fn where_clause(self) -> Option<WhereClause<'a>> { | ||
56 | child_opt(self) | ||
57 | } | ||
58 | } | ||
59 | |||
60 | pub trait AttrsOwner<'a>: AstNode<'a> { | ||
61 | fn attrs(self) -> AstChildren<'a, Attr<'a>> { | ||
62 | children(self) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl<'a> FnDef<'a> { | ||
67 | pub fn has_atom_attr(&self, atom: &str) -> bool { | ||
68 | self.attrs() | ||
69 | .filter_map(|x| x.as_atom()) | ||
70 | .any(|x| x == atom) | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl<'a> Attr<'a> { | ||
75 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
76 | let tt = self.value()?; | ||
77 | let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; | ||
78 | if attr.kind() == IDENT { | ||
79 | Some(attr.leaf_text().unwrap()) | ||
80 | } else { | ||
81 | None | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub fn as_call(&self) -> Option<(SmolStr, TokenTree<'a>)> { | ||
86 | let tt = self.value()?; | ||
87 | let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; | ||
88 | let args = TokenTree::cast(args)?; | ||
89 | if attr.kind() == IDENT { | ||
90 | Some((attr.leaf_text().unwrap(), args)) | ||
91 | } else { | ||
92 | None | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | impl<'a> Lifetime<'a> { | ||
98 | pub fn text(&self) -> SmolStr { | ||
99 | self.syntax().leaf_text().unwrap() | ||
100 | } | ||
101 | } | ||
102 | |||
103 | impl<'a> Name<'a> { | ||
104 | pub fn text(&self) -> SmolStr { | ||
105 | let ident = self.syntax().first_child() | ||
106 | .unwrap(); | ||
107 | ident.leaf_text().unwrap() | ||
108 | } | ||
109 | } | ||
110 | |||
111 | impl<'a> NameRef<'a> { | ||
112 | pub fn text(&self) -> SmolStr { | ||
113 | let ident = self.syntax().first_child() | ||
114 | .unwrap(); | ||
115 | ident.leaf_text().unwrap() | ||
116 | } | ||
117 | } | ||
118 | |||
119 | impl<'a> ImplItem<'a> { | ||
120 | pub fn target_type(self) -> Option<TypeRef<'a>> { | ||
121 | match self.target() { | ||
122 | (Some(t), None) | (_, Some(t)) => Some(t), | ||
123 | _ => None, | ||
124 | } | ||
125 | } | ||
126 | |||
127 | pub fn target_trait(self) -> Option<TypeRef<'a>> { | ||
128 | match self.target() { | ||
129 | (Some(t), Some(_)) => Some(t), | ||
130 | _ => None, | ||
131 | } | ||
132 | } | ||
133 | |||
134 | fn target(self) -> (Option<TypeRef<'a>>, Option<TypeRef<'a>>) { | ||
135 | let mut types = children(self); | ||
136 | let first = types.next(); | ||
137 | let second = types.next(); | ||
138 | (first, second) | ||
139 | } | ||
140 | } | ||
141 | |||
142 | impl<'a> Module<'a> { | ||
143 | pub fn has_semi(self) -> bool { | ||
144 | match self.syntax().last_child() { | ||
145 | None => false, | ||
146 | Some(node) => node.kind() == SEMI, | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | impl<'a> LetStmt<'a> { | ||
152 | pub fn has_semi(self) -> bool { | ||
153 | match self.syntax().last_child() { | ||
154 | None => false, | ||
155 | Some(node) => node.kind() == SEMI, | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | impl<'a> IfExpr<'a> { | ||
161 | pub fn then_branch(self) -> Option<Block<'a>> { | ||
162 | self.blocks().nth(0) | ||
163 | } | ||
164 | pub fn else_branch(self) -> Option<Block<'a>> { | ||
165 | self.blocks().nth(1) | ||
166 | } | ||
167 | fn blocks(self) -> AstChildren<'a, Block<'a>> { | ||
168 | children(self) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> { | ||
173 | children(parent).next() | ||
174 | } | ||
175 | |||
176 | fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C> { | ||
177 | AstChildren::new(parent.syntax()) | ||
178 | } | ||
179 | |||
180 | |||
181 | #[derive(Debug)] | ||
182 | pub struct AstChildren<'a, N> { | ||
183 | inner: SyntaxNodeChildren<RefRoot<'a>>, | ||
184 | ph: PhantomData<N>, | ||
185 | } | ||
186 | |||
187 | impl<'a, N> AstChildren<'a, N> { | ||
188 | fn new(parent: SyntaxNodeRef<'a>) -> Self { | ||
189 | AstChildren { | ||
190 | inner: parent.children(), | ||
191 | ph: PhantomData, | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
196 | impl<'a, N: AstNode<'a>> Iterator for AstChildren<'a, N> { | ||
197 | type Item = N; | ||
198 | fn next(&mut self) -> Option<N> { | ||
199 | loop { | ||
200 | match N::cast(self.inner.next()?) { | ||
201 | Some(n) => return Some(n), | ||
202 | None => (), | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | } | ||