diff options
Diffstat (limited to 'crates/ra_syntax/src')
21 files changed, 1850 insertions, 1848 deletions
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index e2b4f0388..06b45135c 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs | |||
@@ -1,18 +1,14 @@ | |||
1 | pub mod visit; | 1 | pub mod visit; |
2 | 2 | ||
3 | use rowan::TransparentNewType; | 3 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; |
4 | 4 | ||
5 | use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction}; | 5 | pub use rowan::TokenAtOffset; |
6 | 6 | ||
7 | pub use rowan::LeafAtOffset; | 7 | pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset<SyntaxToken> { |
8 | 8 | match node.0.token_at_offset(offset) { | |
9 | pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<&SyntaxNode> { | 9 | TokenAtOffset::None => TokenAtOffset::None, |
10 | match node.0.leaf_at_offset(offset) { | 10 | TokenAtOffset::Single(n) => TokenAtOffset::Single(n.into()), |
11 | LeafAtOffset::None => LeafAtOffset::None, | 11 | TokenAtOffset::Between(l, r) => TokenAtOffset::Between(l.into(), r.into()), |
12 | LeafAtOffset::Single(n) => LeafAtOffset::Single(SyntaxNode::from_repr(n)), | ||
13 | LeafAtOffset::Between(l, r) => { | ||
14 | LeafAtOffset::Between(SyntaxNode::from_repr(l), SyntaxNode::from_repr(r)) | ||
15 | } | ||
16 | } | 12 | } |
17 | } | 13 | } |
18 | 14 | ||
@@ -26,16 +22,29 @@ pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset< | |||
26 | /// | 22 | /// |
27 | /// then the left node will be silently preferred. | 23 | /// then the left node will be silently preferred. |
28 | pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { | 24 | pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { |
29 | find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) | 25 | find_token_at_offset(syntax, offset) |
26 | .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast)) | ||
30 | } | 27 | } |
31 | 28 | ||
32 | /// Finds the first sibling in the given direction which is not `trivia` | 29 | /// Finds the first sibling in the given direction which is not `trivia` |
33 | pub fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> { | 30 | pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { |
34 | node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia()) | 31 | return match element { |
32 | SyntaxElement::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), | ||
33 | SyntaxElement::Token(token) => { | ||
34 | token.siblings_with_tokens(direction).skip(1).find(not_trivia) | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | fn not_trivia(element: &SyntaxElement) -> bool { | ||
39 | match element { | ||
40 | SyntaxElement::Node(_) => true, | ||
41 | SyntaxElement::Token(token) => !token.kind().is_trivia(), | ||
42 | } | ||
43 | } | ||
35 | } | 44 | } |
36 | 45 | ||
37 | pub fn find_covering_node(root: &SyntaxNode, range: TextRange) -> &SyntaxNode { | 46 | pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { |
38 | SyntaxNode::from_repr(root.0.covering_node(range)) | 47 | root.0.covering_node(range).into() |
39 | } | 48 | } |
40 | 49 | ||
41 | // Replace with `std::iter::successors` in `1.34.0` | 50 | // Replace with `std::iter::successors` in `1.34.0` |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index a6fac07c4..9f5c41b0c 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -1,15 +1,24 @@ | |||
1 | //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s | 1 | //! Abstract Syntax Tree, layered on top of untyped `SyntaxNode`s |
2 | |||
2 | mod generated; | 3 | mod generated; |
4 | mod traits; | ||
5 | mod tokens; | ||
6 | mod extensions; | ||
7 | mod expr_extensions; | ||
3 | 8 | ||
4 | use std::marker::PhantomData; | 9 | use std::marker::PhantomData; |
5 | 10 | ||
6 | use itertools::Itertools; | ||
7 | |||
8 | pub use self::generated::*; | ||
9 | use crate::{ | 11 | use crate::{ |
10 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, | 12 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken}, |
11 | SmolStr, | 13 | SmolStr, |
12 | SyntaxKind::*, | 14 | }; |
15 | |||
16 | pub use self::{ | ||
17 | generated::*, | ||
18 | traits::*, | ||
19 | tokens::*, | ||
20 | extensions::{PathSegmentKind, StructKind, SelfParamKind}, | ||
21 | expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind}, | ||
13 | }; | 22 | }; |
14 | 23 | ||
15 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The | 24 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The |
@@ -25,412 +34,18 @@ pub trait AstNode: | |||
25 | fn syntax(&self) -> &SyntaxNode; | 34 | fn syntax(&self) -> &SyntaxNode; |
26 | } | 35 | } |
27 | 36 | ||
28 | pub trait AstToken: AstNode { | 37 | /// Like `AstNode`, but wraps tokens rather than interior nodes. |
29 | fn text(&self) -> &SmolStr { | 38 | pub trait AstToken<'a> { |
30 | self.syntax().leaf_text().unwrap() | 39 | fn cast(token: SyntaxToken<'a>) -> Option<Self> |
31 | } | 40 | where |
32 | } | 41 | Self: Sized; |
33 | 42 | fn syntax(&self) -> SyntaxToken<'a>; | |
34 | pub trait TypeAscriptionOwner: AstNode { | 43 | fn text(&self) -> &'a SmolStr { |
35 | fn ascribed_type(&self) -> Option<&TypeRef> { | 44 | self.syntax().text() |
36 | child_opt(self) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | pub trait NameOwner: AstNode { | ||
41 | fn name(&self) -> Option<&Name> { | ||
42 | child_opt(self) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | pub trait VisibilityOwner: AstNode { | ||
47 | fn visibility(&self) -> Option<&Visibility> { | ||
48 | child_opt(self) | ||
49 | } | ||
50 | } | ||
51 | |||
52 | pub trait LoopBodyOwner: AstNode { | ||
53 | fn loop_body(&self) -> Option<&Block> { | ||
54 | child_opt(self) | ||
55 | } | ||
56 | } | ||
57 | |||
58 | pub trait ArgListOwner: AstNode { | ||
59 | fn arg_list(&self) -> Option<&ArgList> { | ||
60 | child_opt(self) | ||
61 | } | ||
62 | } | ||
63 | |||
64 | pub trait FnDefOwner: AstNode { | ||
65 | fn functions(&self) -> AstChildren<FnDef> { | ||
66 | children(self) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
71 | pub enum ItemOrMacro<'a> { | ||
72 | Item(&'a ModuleItem), | ||
73 | Macro(&'a MacroCall), | ||
74 | } | ||
75 | |||
76 | pub trait ModuleItemOwner: AstNode { | ||
77 | fn items(&self) -> AstChildren<ModuleItem> { | ||
78 | children(self) | ||
79 | } | ||
80 | fn items_with_macros(&self) -> ItemOrMacroIter { | ||
81 | ItemOrMacroIter(self.syntax().children()) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | #[derive(Debug)] | ||
86 | pub struct ItemOrMacroIter<'a>(SyntaxNodeChildren<'a>); | ||
87 | |||
88 | impl<'a> Iterator for ItemOrMacroIter<'a> { | ||
89 | type Item = ItemOrMacro<'a>; | ||
90 | fn next(&mut self) -> Option<ItemOrMacro<'a>> { | ||
91 | loop { | ||
92 | let n = self.0.next()?; | ||
93 | if let Some(item) = ModuleItem::cast(n) { | ||
94 | return Some(ItemOrMacro::Item(item)); | ||
95 | } | ||
96 | if let Some(call) = MacroCall::cast(n) { | ||
97 | return Some(ItemOrMacro::Macro(call)); | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | pub trait TypeParamsOwner: AstNode { | ||
104 | fn type_param_list(&self) -> Option<&TypeParamList> { | ||
105 | child_opt(self) | ||
106 | } | ||
107 | |||
108 | fn where_clause(&self) -> Option<&WhereClause> { | ||
109 | child_opt(self) | ||
110 | } | ||
111 | } | ||
112 | |||
113 | pub trait AttrsOwner: AstNode { | ||
114 | fn attrs(&self) -> AstChildren<Attr> { | ||
115 | children(self) | ||
116 | } | ||
117 | fn has_atom_attr(&self, atom: &str) -> bool { | ||
118 | self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) | ||
119 | } | ||
120 | } | ||
121 | |||
122 | pub trait DocCommentsOwner: AstNode { | ||
123 | fn doc_comments(&self) -> AstChildren<Comment> { | ||
124 | children(self) | ||
125 | } | ||
126 | |||
127 | /// Returns the textual content of a doc comment block as a single string. | ||
128 | /// That is, strips leading `///` (+ optional 1 character of whitespace) | ||
129 | /// and joins lines. | ||
130 | fn doc_comment_text(&self) -> Option<std::string::String> { | ||
131 | let docs = self | ||
132 | .doc_comments() | ||
133 | .filter(|comment| comment.is_doc_comment()) | ||
134 | .map(|comment| { | ||
135 | let prefix_len = comment.prefix().len(); | ||
136 | |||
137 | let line = comment.text().as_str(); | ||
138 | |||
139 | // Determine if the prefix or prefix + 1 char is stripped | ||
140 | let pos = | ||
141 | if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) { | ||
142 | prefix_len + 1 | ||
143 | } else { | ||
144 | prefix_len | ||
145 | }; | ||
146 | |||
147 | line[pos..].to_owned() | ||
148 | }) | ||
149 | .join("\n"); | ||
150 | |||
151 | if docs.is_empty() { | ||
152 | None | ||
153 | } else { | ||
154 | Some(docs) | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl Attr { | ||
160 | pub fn is_inner(&self) -> bool { | ||
161 | let tt = match self.value() { | ||
162 | None => return false, | ||
163 | Some(tt) => tt, | ||
164 | }; | ||
165 | |||
166 | let prev = match tt.syntax().prev_sibling() { | ||
167 | None => return false, | ||
168 | Some(prev) => prev, | ||
169 | }; | ||
170 | |||
171 | prev.kind() == EXCL | ||
172 | } | ||
173 | |||
174 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
175 | let tt = self.value()?; | ||
176 | let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; | ||
177 | if attr.kind() == IDENT { | ||
178 | Some(attr.leaf_text().unwrap().clone()) | ||
179 | } else { | ||
180 | None | ||
181 | } | ||
182 | } | ||
183 | |||
184 | pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { | ||
185 | let tt = self.value()?; | ||
186 | let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; | ||
187 | let args = TokenTree::cast(args)?; | ||
188 | if attr.kind() == IDENT { | ||
189 | Some((attr.leaf_text().unwrap().clone(), args)) | ||
190 | } else { | ||
191 | None | ||
192 | } | ||
193 | } | ||
194 | |||
195 | pub fn as_named(&self) -> Option<SmolStr> { | ||
196 | let tt = self.value()?; | ||
197 | let attr = tt.syntax().children().nth(1)?; | ||
198 | if attr.kind() == IDENT { | ||
199 | Some(attr.leaf_text().unwrap().clone()) | ||
200 | } else { | ||
201 | None | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | impl Comment { | ||
207 | pub fn flavor(&self) -> CommentFlavor { | ||
208 | let text = self.text(); | ||
209 | if text.starts_with("///") { | ||
210 | CommentFlavor::Doc | ||
211 | } else if text.starts_with("//!") { | ||
212 | CommentFlavor::ModuleDoc | ||
213 | } else if text.starts_with("//") { | ||
214 | CommentFlavor::Line | ||
215 | } else { | ||
216 | CommentFlavor::Multiline | ||
217 | } | ||
218 | } | ||
219 | |||
220 | pub fn is_doc_comment(&self) -> bool { | ||
221 | self.flavor().is_doc_comment() | ||
222 | } | ||
223 | |||
224 | pub fn prefix(&self) -> &'static str { | ||
225 | self.flavor().prefix() | ||
226 | } | ||
227 | |||
228 | pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { | ||
229 | self.text().chars().filter(|&c| c == '\n').map(|_| &()) | ||
230 | } | ||
231 | |||
232 | pub fn has_newlines(&self) -> bool { | ||
233 | self.count_newlines_lazy().count() > 0 | ||
234 | } | ||
235 | } | ||
236 | |||
237 | #[derive(Debug, PartialEq, Eq)] | ||
238 | pub enum CommentFlavor { | ||
239 | Line, | ||
240 | Doc, | ||
241 | ModuleDoc, | ||
242 | Multiline, | ||
243 | } | ||
244 | |||
245 | impl CommentFlavor { | ||
246 | pub fn prefix(&self) -> &'static str { | ||
247 | use self::CommentFlavor::*; | ||
248 | match *self { | ||
249 | Line => "//", | ||
250 | Doc => "///", | ||
251 | ModuleDoc => "//!", | ||
252 | Multiline => "/*", | ||
253 | } | ||
254 | } | ||
255 | |||
256 | pub fn is_doc_comment(&self) -> bool { | ||
257 | match self { | ||
258 | CommentFlavor::Doc | CommentFlavor::ModuleDoc => true, | ||
259 | _ => false, | ||
260 | } | ||
261 | } | ||
262 | } | ||
263 | |||
264 | impl Whitespace { | ||
265 | pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { | ||
266 | self.text().chars().filter(|&c| c == '\n').map(|_| &()) | ||
267 | } | ||
268 | |||
269 | pub fn has_newlines(&self) -> bool { | ||
270 | self.text().contains('\n') | ||
271 | } | ||
272 | } | ||
273 | |||
274 | impl Name { | ||
275 | pub fn text(&self) -> &SmolStr { | ||
276 | let ident = self.syntax().first_child().unwrap(); | ||
277 | ident.leaf_text().unwrap() | ||
278 | } | ||
279 | } | ||
280 | |||
281 | impl NameRef { | ||
282 | pub fn text(&self) -> &SmolStr { | ||
283 | let ident = self.syntax().first_child().unwrap(); | ||
284 | ident.leaf_text().unwrap() | ||
285 | } | ||
286 | } | ||
287 | |||
288 | impl ImplBlock { | ||
289 | pub fn target_type(&self) -> Option<&TypeRef> { | ||
290 | match self.target() { | ||
291 | (Some(t), None) | (_, Some(t)) => Some(t), | ||
292 | _ => None, | ||
293 | } | ||
294 | } | ||
295 | |||
296 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
297 | match self.target() { | ||
298 | (Some(t), Some(_)) => Some(t), | ||
299 | _ => None, | ||
300 | } | ||
301 | } | ||
302 | |||
303 | fn target(&self) -> (Option<&TypeRef>, Option<&TypeRef>) { | ||
304 | let mut types = children(self); | ||
305 | let first = types.next(); | ||
306 | let second = types.next(); | ||
307 | (first, second) | ||
308 | } | ||
309 | } | ||
310 | |||
311 | impl Module { | ||
312 | pub fn has_semi(&self) -> bool { | ||
313 | match self.syntax().last_child() { | ||
314 | None => false, | ||
315 | Some(node) => node.kind() == SEMI, | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | |||
320 | impl LetStmt { | ||
321 | pub fn has_semi(&self) -> bool { | ||
322 | match self.syntax().last_child() { | ||
323 | None => false, | ||
324 | Some(node) => node.kind() == SEMI, | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
330 | pub enum ElseBranchFlavor<'a> { | ||
331 | Block(&'a Block), | ||
332 | IfExpr(&'a IfExpr), | ||
333 | } | ||
334 | |||
335 | impl IfExpr { | ||
336 | pub fn then_branch(&self) -> Option<&Block> { | ||
337 | self.blocks().nth(0) | ||
338 | } | ||
339 | pub fn else_branch(&self) -> Option<ElseBranchFlavor> { | ||
340 | let res = match self.blocks().nth(1) { | ||
341 | Some(block) => ElseBranchFlavor::Block(block), | ||
342 | None => { | ||
343 | let elif: &IfExpr = child_opt(self)?; | ||
344 | ElseBranchFlavor::IfExpr(elif) | ||
345 | } | ||
346 | }; | ||
347 | Some(res) | ||
348 | } | ||
349 | |||
350 | fn blocks(&self) -> AstChildren<Block> { | ||
351 | children(self) | ||
352 | } | ||
353 | } | ||
354 | |||
355 | impl ExprStmt { | ||
356 | pub fn has_semi(&self) -> bool { | ||
357 | match self.syntax().last_child() { | ||
358 | None => false, | ||
359 | Some(node) => node.kind() == SEMI, | ||
360 | } | ||
361 | } | ||
362 | } | ||
363 | |||
364 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
365 | pub enum PathSegmentKind<'a> { | ||
366 | Name(&'a NameRef), | ||
367 | SelfKw, | ||
368 | SuperKw, | ||
369 | CrateKw, | ||
370 | } | ||
371 | |||
372 | impl PathSegment { | ||
373 | pub fn parent_path(&self) -> &Path { | ||
374 | self.syntax().parent().and_then(Path::cast).expect("segments are always nested in paths") | ||
375 | } | ||
376 | |||
377 | pub fn kind(&self) -> Option<PathSegmentKind> { | ||
378 | let res = if let Some(name_ref) = self.name_ref() { | ||
379 | PathSegmentKind::Name(name_ref) | ||
380 | } else { | ||
381 | match self.syntax().first_child()?.kind() { | ||
382 | SELF_KW => PathSegmentKind::SelfKw, | ||
383 | SUPER_KW => PathSegmentKind::SuperKw, | ||
384 | CRATE_KW => PathSegmentKind::CrateKw, | ||
385 | _ => return None, | ||
386 | } | ||
387 | }; | ||
388 | Some(res) | ||
389 | } | ||
390 | |||
391 | pub fn has_colon_colon(&self) -> bool { | ||
392 | match self.syntax.first_child().map(|s| s.kind()) { | ||
393 | Some(COLONCOLON) => true, | ||
394 | _ => false, | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | impl Path { | ||
400 | pub fn parent_path(&self) -> Option<&Path> { | ||
401 | self.syntax().parent().and_then(Path::cast) | ||
402 | } | ||
403 | } | ||
404 | |||
405 | impl UseTree { | ||
406 | pub fn has_star(&self) -> bool { | ||
407 | self.syntax().children().any(|it| it.kind() == STAR) | ||
408 | } | ||
409 | } | ||
410 | |||
411 | impl UseTreeList { | ||
412 | pub fn parent_use_tree(&self) -> &UseTree { | ||
413 | self.syntax() | ||
414 | .parent() | ||
415 | .and_then(UseTree::cast) | ||
416 | .expect("UseTreeLists are always nested in UseTrees") | ||
417 | } | ||
418 | } | ||
419 | |||
420 | impl RefPat { | ||
421 | pub fn is_mut(&self) -> bool { | ||
422 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
423 | } | 45 | } |
424 | } | 46 | } |
425 | 47 | ||
426 | fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { | 48 | /// An iterator over `SyntaxNode` children of a particular AST type. |
427 | children(parent).next() | ||
428 | } | ||
429 | |||
430 | fn children<P: AstNode, C: AstNode>(parent: &P) -> AstChildren<C> { | ||
431 | AstChildren::new(parent.syntax()) | ||
432 | } | ||
433 | |||
434 | #[derive(Debug)] | 49 | #[derive(Debug)] |
435 | pub struct AstChildren<'a, N> { | 50 | pub struct AstChildren<'a, N> { |
436 | inner: SyntaxNodeChildren<'a>, | 51 | inner: SyntaxNodeChildren<'a>, |
@@ -446,310 +61,16 @@ impl<'a, N> AstChildren<'a, N> { | |||
446 | impl<'a, N: AstNode + 'a> Iterator for AstChildren<'a, N> { | 61 | impl<'a, N: AstNode + 'a> Iterator for AstChildren<'a, N> { |
447 | type Item = &'a N; | 62 | type Item = &'a N; |
448 | fn next(&mut self) -> Option<&'a N> { | 63 | fn next(&mut self) -> Option<&'a N> { |
449 | loop { | 64 | self.inner.by_ref().find_map(N::cast) |
450 | if let Some(n) = N::cast(self.inner.next()?) { | ||
451 | return Some(n); | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
458 | pub enum StructFlavor<'a> { | ||
459 | Tuple(&'a PosFieldDefList), | ||
460 | Named(&'a NamedFieldDefList), | ||
461 | Unit, | ||
462 | } | ||
463 | |||
464 | impl StructFlavor<'_> { | ||
465 | fn from_node<N: AstNode>(node: &N) -> StructFlavor { | ||
466 | if let Some(nfdl) = child_opt::<_, NamedFieldDefList>(node) { | ||
467 | StructFlavor::Named(nfdl) | ||
468 | } else if let Some(pfl) = child_opt::<_, PosFieldDefList>(node) { | ||
469 | StructFlavor::Tuple(pfl) | ||
470 | } else { | ||
471 | StructFlavor::Unit | ||
472 | } | ||
473 | } | 65 | } |
474 | } | 66 | } |
475 | 67 | ||
476 | impl StructDef { | 68 | fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { |
477 | pub fn flavor(&self) -> StructFlavor { | 69 | children(parent).next() |
478 | StructFlavor::from_node(self) | ||
479 | } | ||
480 | } | ||
481 | |||
482 | impl EnumVariant { | ||
483 | pub fn parent_enum(&self) -> &EnumDef { | ||
484 | self.syntax() | ||
485 | .parent() | ||
486 | .and_then(|it| it.parent()) | ||
487 | .and_then(EnumDef::cast) | ||
488 | .expect("EnumVariants are always nested in Enums") | ||
489 | } | ||
490 | pub fn flavor(&self) -> StructFlavor { | ||
491 | StructFlavor::from_node(self) | ||
492 | } | ||
493 | } | ||
494 | |||
495 | impl PointerType { | ||
496 | pub fn is_mut(&self) -> bool { | ||
497 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
498 | } | ||
499 | } | ||
500 | |||
501 | impl ReferenceType { | ||
502 | pub fn is_mut(&self) -> bool { | ||
503 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
504 | } | ||
505 | } | ||
506 | |||
507 | impl RefExpr { | ||
508 | pub fn is_mut(&self) -> bool { | ||
509 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
510 | } | ||
511 | } | ||
512 | |||
513 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
514 | pub enum PrefixOp { | ||
515 | /// The `*` operator for dereferencing | ||
516 | Deref, | ||
517 | /// The `!` operator for logical inversion | ||
518 | Not, | ||
519 | /// The `-` operator for negation | ||
520 | Neg, | ||
521 | } | ||
522 | |||
523 | impl PrefixExpr { | ||
524 | pub fn op_kind(&self) -> Option<PrefixOp> { | ||
525 | match self.syntax().first_child()?.kind() { | ||
526 | STAR => Some(PrefixOp::Deref), | ||
527 | EXCL => Some(PrefixOp::Not), | ||
528 | MINUS => Some(PrefixOp::Neg), | ||
529 | _ => None, | ||
530 | } | ||
531 | } | ||
532 | |||
533 | pub fn op(&self) -> Option<&SyntaxNode> { | ||
534 | self.syntax().first_child() | ||
535 | } | ||
536 | } | ||
537 | |||
538 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
539 | pub enum BinOp { | ||
540 | /// The `||` operator for boolean OR | ||
541 | BooleanOr, | ||
542 | /// The `&&` operator for boolean AND | ||
543 | BooleanAnd, | ||
544 | /// The `==` operator for equality testing | ||
545 | EqualityTest, | ||
546 | /// The `!=` operator for equality testing | ||
547 | NegatedEqualityTest, | ||
548 | /// The `<=` operator for lesser-equal testing | ||
549 | LesserEqualTest, | ||
550 | /// The `>=` operator for greater-equal testing | ||
551 | GreaterEqualTest, | ||
552 | /// The `<` operator for comparison | ||
553 | LesserTest, | ||
554 | /// The `>` operator for comparison | ||
555 | GreaterTest, | ||
556 | /// The `+` operator for addition | ||
557 | Addition, | ||
558 | /// The `*` operator for multiplication | ||
559 | Multiplication, | ||
560 | /// The `-` operator for subtraction | ||
561 | Subtraction, | ||
562 | /// The `/` operator for division | ||
563 | Division, | ||
564 | /// The `%` operator for remainder after division | ||
565 | Remainder, | ||
566 | /// The `<<` operator for left shift | ||
567 | LeftShift, | ||
568 | /// The `>>` operator for right shift | ||
569 | RightShift, | ||
570 | /// The `^` operator for bitwise XOR | ||
571 | BitwiseXor, | ||
572 | /// The `|` operator for bitwise OR | ||
573 | BitwiseOr, | ||
574 | /// The `&` operator for bitwise AND | ||
575 | BitwiseAnd, | ||
576 | /// The `..` operator for right-open ranges | ||
577 | RangeRightOpen, | ||
578 | /// The `..=` operator for right-closed ranges | ||
579 | RangeRightClosed, | ||
580 | /// The `=` operator for assignment | ||
581 | Assignment, | ||
582 | /// The `+=` operator for assignment after addition | ||
583 | AddAssign, | ||
584 | /// The `/=` operator for assignment after division | ||
585 | DivAssign, | ||
586 | /// The `*=` operator for assignment after multiplication | ||
587 | MulAssign, | ||
588 | /// The `%=` operator for assignment after remainders | ||
589 | RemAssign, | ||
590 | /// The `>>=` operator for assignment after shifting right | ||
591 | ShrAssign, | ||
592 | /// The `<<=` operator for assignment after shifting left | ||
593 | ShlAssign, | ||
594 | /// The `-=` operator for assignment after subtraction | ||
595 | SubAssign, | ||
596 | /// The `|=` operator for assignment after bitwise OR | ||
597 | BitOrAssign, | ||
598 | /// The `&=` operator for assignment after bitwise AND | ||
599 | BitAndAssign, | ||
600 | /// The `^=` operator for assignment after bitwise XOR | ||
601 | BitXorAssign, | ||
602 | } | ||
603 | |||
604 | impl BinExpr { | ||
605 | fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> { | ||
606 | self.syntax().children().find_map(|c| match c.kind() { | ||
607 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | ||
608 | AMPAMP => Some((c, BinOp::BooleanAnd)), | ||
609 | EQEQ => Some((c, BinOp::EqualityTest)), | ||
610 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | ||
611 | LTEQ => Some((c, BinOp::LesserEqualTest)), | ||
612 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | ||
613 | L_ANGLE => Some((c, BinOp::LesserTest)), | ||
614 | R_ANGLE => Some((c, BinOp::GreaterTest)), | ||
615 | PLUS => Some((c, BinOp::Addition)), | ||
616 | STAR => Some((c, BinOp::Multiplication)), | ||
617 | MINUS => Some((c, BinOp::Subtraction)), | ||
618 | SLASH => Some((c, BinOp::Division)), | ||
619 | PERCENT => Some((c, BinOp::Remainder)), | ||
620 | SHL => Some((c, BinOp::LeftShift)), | ||
621 | SHR => Some((c, BinOp::RightShift)), | ||
622 | CARET => Some((c, BinOp::BitwiseXor)), | ||
623 | PIPE => Some((c, BinOp::BitwiseOr)), | ||
624 | AMP => Some((c, BinOp::BitwiseAnd)), | ||
625 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | ||
626 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | ||
627 | EQ => Some((c, BinOp::Assignment)), | ||
628 | PLUSEQ => Some((c, BinOp::AddAssign)), | ||
629 | SLASHEQ => Some((c, BinOp::DivAssign)), | ||
630 | STAREQ => Some((c, BinOp::MulAssign)), | ||
631 | PERCENTEQ => Some((c, BinOp::RemAssign)), | ||
632 | SHREQ => Some((c, BinOp::ShrAssign)), | ||
633 | SHLEQ => Some((c, BinOp::ShlAssign)), | ||
634 | MINUSEQ => Some((c, BinOp::SubAssign)), | ||
635 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | ||
636 | AMPEQ => Some((c, BinOp::BitAndAssign)), | ||
637 | CARETEQ => Some((c, BinOp::BitXorAssign)), | ||
638 | _ => None, | ||
639 | }) | ||
640 | } | ||
641 | |||
642 | pub fn op_kind(&self) -> Option<BinOp> { | ||
643 | self.op_details().map(|t| t.1) | ||
644 | } | ||
645 | |||
646 | pub fn op(&self) -> Option<&SyntaxNode> { | ||
647 | self.op_details().map(|t| t.0) | ||
648 | } | ||
649 | |||
650 | pub fn lhs(&self) -> Option<&Expr> { | ||
651 | children(self).nth(0) | ||
652 | } | ||
653 | |||
654 | pub fn rhs(&self) -> Option<&Expr> { | ||
655 | children(self).nth(1) | ||
656 | } | ||
657 | |||
658 | pub fn sub_exprs(&self) -> (Option<&Expr>, Option<&Expr>) { | ||
659 | let mut children = children(self); | ||
660 | let first = children.next(); | ||
661 | let second = children.next(); | ||
662 | (first, second) | ||
663 | } | ||
664 | } | ||
665 | |||
666 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
667 | pub enum SelfParamFlavor { | ||
668 | /// self | ||
669 | Owned, | ||
670 | /// &self | ||
671 | Ref, | ||
672 | /// &mut self | ||
673 | MutRef, | ||
674 | } | ||
675 | |||
676 | impl SelfParam { | ||
677 | pub fn flavor(&self) -> SelfParamFlavor { | ||
678 | let borrowed = self.syntax().children().any(|n| n.kind() == AMP); | ||
679 | if borrowed { | ||
680 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | ||
681 | if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW) | ||
682 | { | ||
683 | SelfParamFlavor::MutRef | ||
684 | } else { | ||
685 | SelfParamFlavor::Ref | ||
686 | } | ||
687 | } else { | ||
688 | SelfParamFlavor::Owned | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | |||
693 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
694 | pub enum LiteralFlavor { | ||
695 | String, | ||
696 | ByteString, | ||
697 | Char, | ||
698 | Byte, | ||
699 | IntNumber { suffix: Option<SmolStr> }, | ||
700 | FloatNumber { suffix: Option<SmolStr> }, | ||
701 | Bool, | ||
702 | } | ||
703 | |||
704 | impl LiteralExpr { | ||
705 | pub fn flavor(&self) -> LiteralFlavor { | ||
706 | let syntax = self.syntax(); | ||
707 | match syntax.kind() { | ||
708 | INT_NUMBER => { | ||
709 | let allowed_suffix_list = [ | ||
710 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | ||
711 | "u16", "u8", | ||
712 | ]; | ||
713 | let text = syntax.text().to_string(); | ||
714 | let suffix = allowed_suffix_list | ||
715 | .iter() | ||
716 | .find(|&s| text.ends_with(s)) | ||
717 | .map(|&suf| SmolStr::new(suf)); | ||
718 | LiteralFlavor::IntNumber { suffix: suffix } | ||
719 | } | ||
720 | FLOAT_NUMBER => { | ||
721 | let allowed_suffix_list = ["f64", "f32"]; | ||
722 | let text = syntax.text().to_string(); | ||
723 | let suffix = allowed_suffix_list | ||
724 | .iter() | ||
725 | .find(|&s| text.ends_with(s)) | ||
726 | .map(|&suf| SmolStr::new(suf)); | ||
727 | LiteralFlavor::FloatNumber { suffix: suffix } | ||
728 | } | ||
729 | STRING | RAW_STRING => LiteralFlavor::String, | ||
730 | TRUE_KW | FALSE_KW => LiteralFlavor::Bool, | ||
731 | BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString, | ||
732 | CHAR => LiteralFlavor::Char, | ||
733 | BYTE => LiteralFlavor::Byte, | ||
734 | _ => unreachable!(), | ||
735 | } | ||
736 | } | ||
737 | } | ||
738 | |||
739 | impl NamedField { | ||
740 | pub fn parent_struct_lit(&self) -> &StructLit { | ||
741 | self.syntax().ancestors().find_map(StructLit::cast).unwrap() | ||
742 | } | ||
743 | } | 70 | } |
744 | 71 | ||
745 | impl BindPat { | 72 | fn children<P: AstNode, C: AstNode>(parent: &P) -> AstChildren<C> { |
746 | pub fn is_mutable(&self) -> bool { | 73 | AstChildren::new(parent.syntax()) |
747 | self.syntax().children().any(|n| n.kind() == MUT_KW) | ||
748 | } | ||
749 | |||
750 | pub fn is_ref(&self) -> bool { | ||
751 | self.syntax().children().any(|n| n.kind() == REF_KW) | ||
752 | } | ||
753 | } | 74 | } |
754 | 75 | ||
755 | #[test] | 76 | #[test] |
@@ -793,3 +114,70 @@ fn test_doc_comment_preserves_indents() { | |||
793 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 114 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
794 | assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); | 115 | assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); |
795 | } | 116 | } |
117 | |||
118 | #[test] | ||
119 | fn test_where_predicates() { | ||
120 | fn assert_bound(text: &str, bound: Option<&TypeBound>) { | ||
121 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); | ||
122 | } | ||
123 | |||
124 | let file = SourceFile::parse( | ||
125 | r#" | ||
126 | fn foo() | ||
127 | where | ||
128 | T: Clone + Copy + Debug + 'static, | ||
129 | 'a: 'b + 'c, | ||
130 | Iterator::Item: 'a + Debug, | ||
131 | Iterator::Item: Debug + 'a, | ||
132 | <T as Iterator>::Item: Debug + 'a, | ||
133 | for<'a> F: Fn(&'a str) | ||
134 | {} | ||
135 | "#, | ||
136 | ); | ||
137 | let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap(); | ||
138 | |||
139 | let mut predicates = where_clause.predicates(); | ||
140 | |||
141 | let pred = predicates.next().unwrap(); | ||
142 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
143 | |||
144 | assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string()); | ||
145 | assert_bound("Clone", bounds.next()); | ||
146 | assert_bound("Copy", bounds.next()); | ||
147 | assert_bound("Debug", bounds.next()); | ||
148 | assert_bound("'static", bounds.next()); | ||
149 | |||
150 | let pred = predicates.next().unwrap(); | ||
151 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
152 | |||
153 | assert_eq!("'a", pred.lifetime_token().unwrap().text()); | ||
154 | |||
155 | assert_bound("'b", bounds.next()); | ||
156 | assert_bound("'c", bounds.next()); | ||
157 | |||
158 | let pred = predicates.next().unwrap(); | ||
159 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
160 | |||
161 | assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string()); | ||
162 | assert_bound("'a", bounds.next()); | ||
163 | |||
164 | let pred = predicates.next().unwrap(); | ||
165 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
166 | |||
167 | assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string()); | ||
168 | assert_bound("Debug", bounds.next()); | ||
169 | assert_bound("'a", bounds.next()); | ||
170 | |||
171 | let pred = predicates.next().unwrap(); | ||
172 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
173 | |||
174 | assert_eq!("<T as Iterator>::Item", pred.type_ref().unwrap().syntax().text().to_string()); | ||
175 | assert_bound("Debug", bounds.next()); | ||
176 | assert_bound("'a", bounds.next()); | ||
177 | |||
178 | let pred = predicates.next().unwrap(); | ||
179 | let mut bounds = pred.type_bound_list().unwrap().bounds(); | ||
180 | |||
181 | assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string()); | ||
182 | assert_bound("Fn(&'a str)", bounds.next()); | ||
183 | } | ||
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs new file mode 100644 index 000000000..1d8313810 --- /dev/null +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -0,0 +1,252 @@ | |||
1 | //! Various extension methods to ast Expr Nodes, which are hard to code-generate. | ||
2 | |||
3 | use crate::{ | ||
4 | SyntaxToken, SyntaxElement, SmolStr, | ||
5 | ast::{self, AstNode, AstChildren, children, child_opt}, | ||
6 | SyntaxKind::* | ||
7 | }; | ||
8 | |||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
10 | pub enum ElseBranch<'a> { | ||
11 | Block(&'a ast::Block), | ||
12 | IfExpr(&'a ast::IfExpr), | ||
13 | } | ||
14 | |||
15 | impl ast::IfExpr { | ||
16 | pub fn then_branch(&self) -> Option<&ast::Block> { | ||
17 | self.blocks().nth(0) | ||
18 | } | ||
19 | pub fn else_branch(&self) -> Option<ElseBranch> { | ||
20 | let res = match self.blocks().nth(1) { | ||
21 | Some(block) => ElseBranch::Block(block), | ||
22 | None => { | ||
23 | let elif: &ast::IfExpr = child_opt(self)?; | ||
24 | ElseBranch::IfExpr(elif) | ||
25 | } | ||
26 | }; | ||
27 | Some(res) | ||
28 | } | ||
29 | |||
30 | fn blocks(&self) -> AstChildren<ast::Block> { | ||
31 | children(self) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | impl ast::RefExpr { | ||
36 | pub fn is_mut(&self) -> bool { | ||
37 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
38 | } | ||
39 | } | ||
40 | |||
41 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
42 | pub enum PrefixOp { | ||
43 | /// The `*` operator for dereferencing | ||
44 | Deref, | ||
45 | /// The `!` operator for logical inversion | ||
46 | Not, | ||
47 | /// The `-` operator for negation | ||
48 | Neg, | ||
49 | } | ||
50 | |||
51 | impl ast::PrefixExpr { | ||
52 | pub fn op_kind(&self) -> Option<PrefixOp> { | ||
53 | match self.op_token()?.kind() { | ||
54 | STAR => Some(PrefixOp::Deref), | ||
55 | EXCL => Some(PrefixOp::Not), | ||
56 | MINUS => Some(PrefixOp::Neg), | ||
57 | _ => None, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
62 | self.syntax().first_child_or_token()?.as_token() | ||
63 | } | ||
64 | } | ||
65 | |||
66 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
67 | pub enum BinOp { | ||
68 | /// The `||` operator for boolean OR | ||
69 | BooleanOr, | ||
70 | /// The `&&` operator for boolean AND | ||
71 | BooleanAnd, | ||
72 | /// The `==` operator for equality testing | ||
73 | EqualityTest, | ||
74 | /// The `!=` operator for equality testing | ||
75 | NegatedEqualityTest, | ||
76 | /// The `<=` operator for lesser-equal testing | ||
77 | LesserEqualTest, | ||
78 | /// The `>=` operator for greater-equal testing | ||
79 | GreaterEqualTest, | ||
80 | /// The `<` operator for comparison | ||
81 | LesserTest, | ||
82 | /// The `>` operator for comparison | ||
83 | GreaterTest, | ||
84 | /// The `+` operator for addition | ||
85 | Addition, | ||
86 | /// The `*` operator for multiplication | ||
87 | Multiplication, | ||
88 | /// The `-` operator for subtraction | ||
89 | Subtraction, | ||
90 | /// The `/` operator for division | ||
91 | Division, | ||
92 | /// The `%` operator for remainder after division | ||
93 | Remainder, | ||
94 | /// The `<<` operator for left shift | ||
95 | LeftShift, | ||
96 | /// The `>>` operator for right shift | ||
97 | RightShift, | ||
98 | /// The `^` operator for bitwise XOR | ||
99 | BitwiseXor, | ||
100 | /// The `|` operator for bitwise OR | ||
101 | BitwiseOr, | ||
102 | /// The `&` operator for bitwise AND | ||
103 | BitwiseAnd, | ||
104 | /// The `..` operator for right-open ranges | ||
105 | RangeRightOpen, | ||
106 | /// The `..=` operator for right-closed ranges | ||
107 | RangeRightClosed, | ||
108 | /// The `=` operator for assignment | ||
109 | Assignment, | ||
110 | /// The `+=` operator for assignment after addition | ||
111 | AddAssign, | ||
112 | /// The `/=` operator for assignment after division | ||
113 | DivAssign, | ||
114 | /// The `*=` operator for assignment after multiplication | ||
115 | MulAssign, | ||
116 | /// The `%=` operator for assignment after remainders | ||
117 | RemAssign, | ||
118 | /// The `>>=` operator for assignment after shifting right | ||
119 | ShrAssign, | ||
120 | /// The `<<=` operator for assignment after shifting left | ||
121 | ShlAssign, | ||
122 | /// The `-=` operator for assignment after subtraction | ||
123 | SubAssign, | ||
124 | /// The `|=` operator for assignment after bitwise OR | ||
125 | BitOrAssign, | ||
126 | /// The `&=` operator for assignment after bitwise AND | ||
127 | BitAndAssign, | ||
128 | /// The `^=` operator for assignment after bitwise XOR | ||
129 | BitXorAssign, | ||
130 | } | ||
131 | |||
132 | impl ast::BinExpr { | ||
133 | fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { | ||
134 | self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { | ||
135 | match c.kind() { | ||
136 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | ||
137 | AMPAMP => Some((c, BinOp::BooleanAnd)), | ||
138 | EQEQ => Some((c, BinOp::EqualityTest)), | ||
139 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | ||
140 | LTEQ => Some((c, BinOp::LesserEqualTest)), | ||
141 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | ||
142 | L_ANGLE => Some((c, BinOp::LesserTest)), | ||
143 | R_ANGLE => Some((c, BinOp::GreaterTest)), | ||
144 | PLUS => Some((c, BinOp::Addition)), | ||
145 | STAR => Some((c, BinOp::Multiplication)), | ||
146 | MINUS => Some((c, BinOp::Subtraction)), | ||
147 | SLASH => Some((c, BinOp::Division)), | ||
148 | PERCENT => Some((c, BinOp::Remainder)), | ||
149 | SHL => Some((c, BinOp::LeftShift)), | ||
150 | SHR => Some((c, BinOp::RightShift)), | ||
151 | CARET => Some((c, BinOp::BitwiseXor)), | ||
152 | PIPE => Some((c, BinOp::BitwiseOr)), | ||
153 | AMP => Some((c, BinOp::BitwiseAnd)), | ||
154 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | ||
155 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | ||
156 | EQ => Some((c, BinOp::Assignment)), | ||
157 | PLUSEQ => Some((c, BinOp::AddAssign)), | ||
158 | SLASHEQ => Some((c, BinOp::DivAssign)), | ||
159 | STAREQ => Some((c, BinOp::MulAssign)), | ||
160 | PERCENTEQ => Some((c, BinOp::RemAssign)), | ||
161 | SHREQ => Some((c, BinOp::ShrAssign)), | ||
162 | SHLEQ => Some((c, BinOp::ShlAssign)), | ||
163 | MINUSEQ => Some((c, BinOp::SubAssign)), | ||
164 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | ||
165 | AMPEQ => Some((c, BinOp::BitAndAssign)), | ||
166 | CARETEQ => Some((c, BinOp::BitXorAssign)), | ||
167 | _ => None, | ||
168 | } | ||
169 | }) | ||
170 | } | ||
171 | |||
172 | pub fn op_kind(&self) -> Option<BinOp> { | ||
173 | self.op_details().map(|t| t.1) | ||
174 | } | ||
175 | |||
176 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
177 | self.op_details().map(|t| t.0) | ||
178 | } | ||
179 | |||
180 | pub fn lhs(&self) -> Option<&ast::Expr> { | ||
181 | children(self).nth(0) | ||
182 | } | ||
183 | |||
184 | pub fn rhs(&self) -> Option<&ast::Expr> { | ||
185 | children(self).nth(1) | ||
186 | } | ||
187 | |||
188 | pub fn sub_exprs(&self) -> (Option<&ast::Expr>, Option<&ast::Expr>) { | ||
189 | let mut children = children(self); | ||
190 | let first = children.next(); | ||
191 | let second = children.next(); | ||
192 | (first, second) | ||
193 | } | ||
194 | } | ||
195 | |||
196 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
197 | pub enum LiteralKind { | ||
198 | String, | ||
199 | ByteString, | ||
200 | Char, | ||
201 | Byte, | ||
202 | IntNumber { suffix: Option<SmolStr> }, | ||
203 | FloatNumber { suffix: Option<SmolStr> }, | ||
204 | Bool, | ||
205 | } | ||
206 | |||
207 | impl ast::Literal { | ||
208 | pub fn token(&self) -> SyntaxToken { | ||
209 | match self.syntax().first_child_or_token().unwrap() { | ||
210 | SyntaxElement::Token(token) => token, | ||
211 | _ => unreachable!(), | ||
212 | } | ||
213 | } | ||
214 | |||
215 | pub fn kind(&self) -> LiteralKind { | ||
216 | match self.token().kind() { | ||
217 | INT_NUMBER => { | ||
218 | let allowed_suffix_list = [ | ||
219 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | ||
220 | "u16", "u8", | ||
221 | ]; | ||
222 | let text = self.token().text().to_string(); | ||
223 | let suffix = allowed_suffix_list | ||
224 | .iter() | ||
225 | .find(|&s| text.ends_with(s)) | ||
226 | .map(|&suf| SmolStr::new(suf)); | ||
227 | LiteralKind::IntNumber { suffix } | ||
228 | } | ||
229 | FLOAT_NUMBER => { | ||
230 | let allowed_suffix_list = ["f64", "f32"]; | ||
231 | let text = self.token().text().to_string(); | ||
232 | let suffix = allowed_suffix_list | ||
233 | .iter() | ||
234 | .find(|&s| text.ends_with(s)) | ||
235 | .map(|&suf| SmolStr::new(suf)); | ||
236 | LiteralKind::FloatNumber { suffix: suffix } | ||
237 | } | ||
238 | STRING | RAW_STRING => LiteralKind::String, | ||
239 | TRUE_KW | FALSE_KW => LiteralKind::Bool, | ||
240 | BYTE_STRING | RAW_BYTE_STRING => LiteralKind::ByteString, | ||
241 | CHAR => LiteralKind::Char, | ||
242 | BYTE => LiteralKind::Byte, | ||
243 | _ => unreachable!(), | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | impl ast::NamedField { | ||
249 | pub fn parent_struct_lit(&self) -> &ast::StructLit { | ||
250 | self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap() | ||
251 | } | ||
252 | } | ||
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs new file mode 100644 index 000000000..aec57c380 --- /dev/null +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -0,0 +1,303 @@ | |||
1 | //! Various extension methods to ast Nodes, which are hard to code-generate. | ||
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | ||
3 | |||
4 | use itertools::Itertools; | ||
5 | |||
6 | use crate::{ | ||
7 | SmolStr, SyntaxToken, | ||
8 | ast::{self, AstNode, children, child_opt}, | ||
9 | SyntaxKind::*, | ||
10 | }; | ||
11 | |||
12 | impl ast::Name { | ||
13 | pub fn text(&self) -> &SmolStr { | ||
14 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
15 | ident.text() | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl ast::NameRef { | ||
20 | pub fn text(&self) -> &SmolStr { | ||
21 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
22 | ident.text() | ||
23 | } | ||
24 | } | ||
25 | |||
26 | impl ast::Attr { | ||
27 | pub fn is_inner(&self) -> bool { | ||
28 | let tt = match self.value() { | ||
29 | None => return false, | ||
30 | Some(tt) => tt, | ||
31 | }; | ||
32 | |||
33 | let prev = match tt.syntax().prev_sibling() { | ||
34 | None => return false, | ||
35 | Some(prev) => prev, | ||
36 | }; | ||
37 | |||
38 | prev.kind() == EXCL | ||
39 | } | ||
40 | |||
41 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
42 | let tt = self.value()?; | ||
43 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
44 | if attr.kind() == IDENT { | ||
45 | Some(attr.as_token()?.text().clone()) | ||
46 | } else { | ||
47 | None | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub fn as_call(&self) -> Option<(SmolStr, &ast::TokenTree)> { | ||
52 | let tt = self.value()?; | ||
53 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
54 | let args = ast::TokenTree::cast(args.as_node()?)?; | ||
55 | if attr.kind() == IDENT { | ||
56 | Some((attr.as_token()?.text().clone(), args)) | ||
57 | } else { | ||
58 | None | ||
59 | } | ||
60 | } | ||
61 | |||
62 | pub fn as_named(&self) -> Option<SmolStr> { | ||
63 | let tt = self.value()?; | ||
64 | let attr = tt.syntax().children_with_tokens().nth(1)?; | ||
65 | if attr.kind() == IDENT { | ||
66 | Some(attr.as_token()?.text().clone()) | ||
67 | } else { | ||
68 | None | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
74 | pub enum PathSegmentKind<'a> { | ||
75 | Name(&'a ast::NameRef), | ||
76 | SelfKw, | ||
77 | SuperKw, | ||
78 | CrateKw, | ||
79 | } | ||
80 | |||
81 | impl ast::PathSegment { | ||
82 | pub fn parent_path(&self) -> &ast::Path { | ||
83 | self.syntax() | ||
84 | .parent() | ||
85 | .and_then(ast::Path::cast) | ||
86 | .expect("segments are always nested in paths") | ||
87 | } | ||
88 | |||
89 | pub fn kind(&self) -> Option<PathSegmentKind> { | ||
90 | let res = if let Some(name_ref) = self.name_ref() { | ||
91 | PathSegmentKind::Name(name_ref) | ||
92 | } else { | ||
93 | match self.syntax().first_child_or_token()?.kind() { | ||
94 | SELF_KW => PathSegmentKind::SelfKw, | ||
95 | SUPER_KW => PathSegmentKind::SuperKw, | ||
96 | CRATE_KW => PathSegmentKind::CrateKw, | ||
97 | _ => return None, | ||
98 | } | ||
99 | }; | ||
100 | Some(res) | ||
101 | } | ||
102 | |||
103 | pub fn has_colon_colon(&self) -> bool { | ||
104 | match self.syntax.first_child_or_token().map(|s| s.kind()) { | ||
105 | Some(COLONCOLON) => true, | ||
106 | _ => false, | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | impl ast::Path { | ||
112 | pub fn parent_path(&self) -> Option<&ast::Path> { | ||
113 | self.syntax().parent().and_then(ast::Path::cast) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | impl ast::Module { | ||
118 | pub fn has_semi(&self) -> bool { | ||
119 | match self.syntax().last_child_or_token() { | ||
120 | None => false, | ||
121 | Some(node) => node.kind() == SEMI, | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | impl ast::UseTree { | ||
127 | pub fn has_star(&self) -> bool { | ||
128 | self.syntax().children_with_tokens().any(|it| it.kind() == STAR) | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl ast::UseTreeList { | ||
133 | pub fn parent_use_tree(&self) -> &ast::UseTree { | ||
134 | self.syntax() | ||
135 | .parent() | ||
136 | .and_then(ast::UseTree::cast) | ||
137 | .expect("UseTreeLists are always nested in UseTrees") | ||
138 | } | ||
139 | } | ||
140 | |||
141 | impl ast::ImplBlock { | ||
142 | pub fn target_type(&self) -> Option<&ast::TypeRef> { | ||
143 | match self.target() { | ||
144 | (Some(t), None) | (_, Some(t)) => Some(t), | ||
145 | _ => None, | ||
146 | } | ||
147 | } | ||
148 | |||
149 | pub fn target_trait(&self) -> Option<&ast::TypeRef> { | ||
150 | match self.target() { | ||
151 | (Some(t), Some(_)) => Some(t), | ||
152 | _ => None, | ||
153 | } | ||
154 | } | ||
155 | |||
156 | fn target(&self) -> (Option<&ast::TypeRef>, Option<&ast::TypeRef>) { | ||
157 | let mut types = children(self); | ||
158 | let first = types.next(); | ||
159 | let second = types.next(); | ||
160 | (first, second) | ||
161 | } | ||
162 | } | ||
163 | |||
164 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
165 | pub enum StructKind<'a> { | ||
166 | Tuple(&'a ast::PosFieldDefList), | ||
167 | Named(&'a ast::NamedFieldDefList), | ||
168 | Unit, | ||
169 | } | ||
170 | |||
171 | impl StructKind<'_> { | ||
172 | fn from_node<N: AstNode>(node: &N) -> StructKind { | ||
173 | if let Some(nfdl) = child_opt::<_, ast::NamedFieldDefList>(node) { | ||
174 | StructKind::Named(nfdl) | ||
175 | } else if let Some(pfl) = child_opt::<_, ast::PosFieldDefList>(node) { | ||
176 | StructKind::Tuple(pfl) | ||
177 | } else { | ||
178 | StructKind::Unit | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | impl ast::StructDef { | ||
184 | pub fn kind(&self) -> StructKind { | ||
185 | StructKind::from_node(self) | ||
186 | } | ||
187 | } | ||
188 | |||
189 | impl ast::EnumVariant { | ||
190 | pub fn parent_enum(&self) -> &ast::EnumDef { | ||
191 | self.syntax() | ||
192 | .parent() | ||
193 | .and_then(|it| it.parent()) | ||
194 | .and_then(ast::EnumDef::cast) | ||
195 | .expect("EnumVariants are always nested in Enums") | ||
196 | } | ||
197 | pub fn kind(&self) -> StructKind { | ||
198 | StructKind::from_node(self) | ||
199 | } | ||
200 | } | ||
201 | |||
202 | impl ast::LetStmt { | ||
203 | pub fn has_semi(&self) -> bool { | ||
204 | match self.syntax().last_child_or_token() { | ||
205 | None => false, | ||
206 | Some(node) => node.kind() == SEMI, | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | impl ast::ExprStmt { | ||
212 | pub fn has_semi(&self) -> bool { | ||
213 | match self.syntax().last_child_or_token() { | ||
214 | None => false, | ||
215 | Some(node) => node.kind() == SEMI, | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | |||
220 | impl ast::RefPat { | ||
221 | pub fn is_mut(&self) -> bool { | ||
222 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
223 | } | ||
224 | } | ||
225 | |||
226 | impl ast::BindPat { | ||
227 | pub fn is_mutable(&self) -> bool { | ||
228 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
229 | } | ||
230 | |||
231 | pub fn is_ref(&self) -> bool { | ||
232 | self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW) | ||
233 | } | ||
234 | } | ||
235 | |||
236 | impl ast::PointerType { | ||
237 | pub fn is_mut(&self) -> bool { | ||
238 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
239 | } | ||
240 | } | ||
241 | |||
242 | impl ast::ReferenceType { | ||
243 | pub fn is_mut(&self) -> bool { | ||
244 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
245 | } | ||
246 | } | ||
247 | |||
248 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
249 | pub enum SelfParamKind { | ||
250 | /// self | ||
251 | Owned, | ||
252 | /// &self | ||
253 | Ref, | ||
254 | /// &mut self | ||
255 | MutRef, | ||
256 | } | ||
257 | |||
258 | impl ast::SelfParam { | ||
259 | pub fn self_kw_token(&self) -> SyntaxToken { | ||
260 | self.syntax() | ||
261 | .children_with_tokens() | ||
262 | .filter_map(|it| it.as_token()) | ||
263 | .find(|it| it.kind() == SELF_KW) | ||
264 | .expect("invalid tree: self param must have self") | ||
265 | } | ||
266 | |||
267 | pub fn kind(&self) -> SelfParamKind { | ||
268 | let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP); | ||
269 | if borrowed { | ||
270 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | ||
271 | if self | ||
272 | .syntax() | ||
273 | .children_with_tokens() | ||
274 | .skip_while(|n| n.kind() != AMP) | ||
275 | .any(|n| n.kind() == MUT_KW) | ||
276 | { | ||
277 | SelfParamKind::MutRef | ||
278 | } else { | ||
279 | SelfParamKind::Ref | ||
280 | } | ||
281 | } else { | ||
282 | SelfParamKind::Owned | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | impl ast::LifetimeParam { | ||
288 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
289 | self.syntax() | ||
290 | .children_with_tokens() | ||
291 | .filter_map(|it| it.as_token()) | ||
292 | .find(|it| it.kind() == LIFETIME) | ||
293 | } | ||
294 | } | ||
295 | |||
296 | impl ast::WherePred { | ||
297 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
298 | self.syntax() | ||
299 | .children_with_tokens() | ||
300 | .filter_map(|it| it.as_token()) | ||
301 | .find(|it| it.kind() == LIFETIME) | ||
302 | } | ||
303 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 47a37e4d1..0376c91c8 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -376,64 +376,6 @@ impl BreakExpr { | |||
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | // Byte | ||
380 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
381 | #[repr(transparent)] | ||
382 | pub struct Byte { | ||
383 | pub(crate) syntax: SyntaxNode, | ||
384 | } | ||
385 | unsafe impl TransparentNewType for Byte { | ||
386 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
387 | } | ||
388 | |||
389 | impl AstNode for Byte { | ||
390 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
391 | match syntax.kind() { | ||
392 | BYTE => Some(Byte::from_repr(syntax.into_repr())), | ||
393 | _ => None, | ||
394 | } | ||
395 | } | ||
396 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
397 | } | ||
398 | |||
399 | impl ToOwned for Byte { | ||
400 | type Owned = TreeArc<Byte>; | ||
401 | fn to_owned(&self) -> TreeArc<Byte> { TreeArc::cast(self.syntax.to_owned()) } | ||
402 | } | ||
403 | |||
404 | |||
405 | impl ast::AstToken for Byte {} | ||
406 | impl Byte {} | ||
407 | |||
408 | // ByteString | ||
409 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
410 | #[repr(transparent)] | ||
411 | pub struct ByteString { | ||
412 | pub(crate) syntax: SyntaxNode, | ||
413 | } | ||
414 | unsafe impl TransparentNewType for ByteString { | ||
415 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
416 | } | ||
417 | |||
418 | impl AstNode for ByteString { | ||
419 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
420 | match syntax.kind() { | ||
421 | BYTE_STRING => Some(ByteString::from_repr(syntax.into_repr())), | ||
422 | _ => None, | ||
423 | } | ||
424 | } | ||
425 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
426 | } | ||
427 | |||
428 | impl ToOwned for ByteString { | ||
429 | type Owned = TreeArc<ByteString>; | ||
430 | fn to_owned(&self) -> TreeArc<ByteString> { TreeArc::cast(self.syntax.to_owned()) } | ||
431 | } | ||
432 | |||
433 | |||
434 | impl ast::AstToken for ByteString {} | ||
435 | impl ByteString {} | ||
436 | |||
437 | // CallExpr | 379 | // CallExpr |
438 | #[derive(Debug, PartialEq, Eq, Hash)] | 380 | #[derive(Debug, PartialEq, Eq, Hash)] |
439 | #[repr(transparent)] | 381 | #[repr(transparent)] |
@@ -503,64 +445,6 @@ impl CastExpr { | |||
503 | } | 445 | } |
504 | } | 446 | } |
505 | 447 | ||
506 | // Char | ||
507 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
508 | #[repr(transparent)] | ||
509 | pub struct Char { | ||
510 | pub(crate) syntax: SyntaxNode, | ||
511 | } | ||
512 | unsafe impl TransparentNewType for Char { | ||
513 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
514 | } | ||
515 | |||
516 | impl AstNode for Char { | ||
517 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
518 | match syntax.kind() { | ||
519 | CHAR => Some(Char::from_repr(syntax.into_repr())), | ||
520 | _ => None, | ||
521 | } | ||
522 | } | ||
523 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
524 | } | ||
525 | |||
526 | impl ToOwned for Char { | ||
527 | type Owned = TreeArc<Char>; | ||
528 | fn to_owned(&self) -> TreeArc<Char> { TreeArc::cast(self.syntax.to_owned()) } | ||
529 | } | ||
530 | |||
531 | |||
532 | impl ast::AstToken for Char {} | ||
533 | impl Char {} | ||
534 | |||
535 | // Comment | ||
536 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
537 | #[repr(transparent)] | ||
538 | pub struct Comment { | ||
539 | pub(crate) syntax: SyntaxNode, | ||
540 | } | ||
541 | unsafe impl TransparentNewType for Comment { | ||
542 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
543 | } | ||
544 | |||
545 | impl AstNode for Comment { | ||
546 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
547 | match syntax.kind() { | ||
548 | COMMENT => Some(Comment::from_repr(syntax.into_repr())), | ||
549 | _ => None, | ||
550 | } | ||
551 | } | ||
552 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
553 | } | ||
554 | |||
555 | impl ToOwned for Comment { | ||
556 | type Owned = TreeArc<Comment>; | ||
557 | fn to_owned(&self) -> TreeArc<Comment> { TreeArc::cast(self.syntax.to_owned()) } | ||
558 | } | ||
559 | |||
560 | |||
561 | impl ast::AstToken for Comment {} | ||
562 | impl Comment {} | ||
563 | |||
564 | // Condition | 448 | // Condition |
565 | #[derive(Debug, PartialEq, Eq, Hash)] | 449 | #[derive(Debug, PartialEq, Eq, Hash)] |
566 | #[repr(transparent)] | 450 | #[repr(transparent)] |
@@ -629,7 +513,11 @@ impl ast::TypeParamsOwner for ConstDef {} | |||
629 | impl ast::AttrsOwner for ConstDef {} | 513 | impl ast::AttrsOwner for ConstDef {} |
630 | impl ast::DocCommentsOwner for ConstDef {} | 514 | impl ast::DocCommentsOwner for ConstDef {} |
631 | impl ast::TypeAscriptionOwner for ConstDef {} | 515 | impl ast::TypeAscriptionOwner for ConstDef {} |
632 | impl ConstDef {} | 516 | impl ConstDef { |
517 | pub fn body(&self) -> Option<&Expr> { | ||
518 | super::child_opt(self) | ||
519 | } | ||
520 | } | ||
633 | 521 | ||
634 | // ContinueExpr | 522 | // ContinueExpr |
635 | #[derive(Debug, PartialEq, Eq, Hash)] | 523 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -685,6 +573,7 @@ impl ToOwned for DynTraitType { | |||
685 | } | 573 | } |
686 | 574 | ||
687 | 575 | ||
576 | impl ast::TypeBoundsOwner for DynTraitType {} | ||
688 | impl DynTraitType {} | 577 | impl DynTraitType {} |
689 | 578 | ||
690 | // EnumDef | 579 | // EnumDef |
@@ -830,6 +719,7 @@ pub enum ExprKind<'a> { | |||
830 | RangeExpr(&'a RangeExpr), | 719 | RangeExpr(&'a RangeExpr), |
831 | BinExpr(&'a BinExpr), | 720 | BinExpr(&'a BinExpr), |
832 | Literal(&'a Literal), | 721 | Literal(&'a Literal), |
722 | MacroCall(&'a MacroCall), | ||
833 | } | 723 | } |
834 | impl<'a> From<&'a TupleExpr> for &'a Expr { | 724 | impl<'a> From<&'a TupleExpr> for &'a Expr { |
835 | fn from(n: &'a TupleExpr) -> &'a Expr { | 725 | fn from(n: &'a TupleExpr) -> &'a Expr { |
@@ -966,6 +856,11 @@ impl<'a> From<&'a Literal> for &'a Expr { | |||
966 | Expr::cast(&n.syntax).unwrap() | 856 | Expr::cast(&n.syntax).unwrap() |
967 | } | 857 | } |
968 | } | 858 | } |
859 | impl<'a> From<&'a MacroCall> for &'a Expr { | ||
860 | fn from(n: &'a MacroCall) -> &'a Expr { | ||
861 | Expr::cast(&n.syntax).unwrap() | ||
862 | } | ||
863 | } | ||
969 | 864 | ||
970 | 865 | ||
971 | impl AstNode for Expr { | 866 | impl AstNode for Expr { |
@@ -997,7 +892,8 @@ impl AstNode for Expr { | |||
997 | | PREFIX_EXPR | 892 | | PREFIX_EXPR |
998 | | RANGE_EXPR | 893 | | RANGE_EXPR |
999 | | BIN_EXPR | 894 | | BIN_EXPR |
1000 | | LITERAL => Some(Expr::from_repr(syntax.into_repr())), | 895 | | LITERAL |
896 | | MACRO_CALL => Some(Expr::from_repr(syntax.into_repr())), | ||
1001 | _ => None, | 897 | _ => None, |
1002 | } | 898 | } |
1003 | } | 899 | } |
@@ -1039,6 +935,7 @@ impl Expr { | |||
1039 | RANGE_EXPR => ExprKind::RangeExpr(RangeExpr::cast(&self.syntax).unwrap()), | 935 | RANGE_EXPR => ExprKind::RangeExpr(RangeExpr::cast(&self.syntax).unwrap()), |
1040 | BIN_EXPR => ExprKind::BinExpr(BinExpr::cast(&self.syntax).unwrap()), | 936 | BIN_EXPR => ExprKind::BinExpr(BinExpr::cast(&self.syntax).unwrap()), |
1041 | LITERAL => ExprKind::Literal(Literal::cast(&self.syntax).unwrap()), | 937 | LITERAL => ExprKind::Literal(Literal::cast(&self.syntax).unwrap()), |
938 | MACRO_CALL => ExprKind::MacroCall(MacroCall::cast(&self.syntax).unwrap()), | ||
1042 | _ => unreachable!(), | 939 | _ => unreachable!(), |
1043 | } | 940 | } |
1044 | } | 941 | } |
@@ -1114,35 +1011,6 @@ impl ExternCrateItem { | |||
1114 | } | 1011 | } |
1115 | } | 1012 | } |
1116 | 1013 | ||
1117 | // FalseKw | ||
1118 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1119 | #[repr(transparent)] | ||
1120 | pub struct FalseKw { | ||
1121 | pub(crate) syntax: SyntaxNode, | ||
1122 | } | ||
1123 | unsafe impl TransparentNewType for FalseKw { | ||
1124 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1125 | } | ||
1126 | |||
1127 | impl AstNode for FalseKw { | ||
1128 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1129 | match syntax.kind() { | ||
1130 | FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())), | ||
1131 | _ => None, | ||
1132 | } | ||
1133 | } | ||
1134 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1135 | } | ||
1136 | |||
1137 | impl ToOwned for FalseKw { | ||
1138 | type Owned = TreeArc<FalseKw>; | ||
1139 | fn to_owned(&self) -> TreeArc<FalseKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | impl ast::AstToken for FalseKw {} | ||
1144 | impl FalseKw {} | ||
1145 | |||
1146 | // FieldExpr | 1014 | // FieldExpr |
1147 | #[derive(Debug, PartialEq, Eq, Hash)] | 1015 | #[derive(Debug, PartialEq, Eq, Hash)] |
1148 | #[repr(transparent)] | 1016 | #[repr(transparent)] |
@@ -1248,35 +1116,6 @@ impl FieldPatList { | |||
1248 | } | 1116 | } |
1249 | } | 1117 | } |
1250 | 1118 | ||
1251 | // FloatNumber | ||
1252 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1253 | #[repr(transparent)] | ||
1254 | pub struct FloatNumber { | ||
1255 | pub(crate) syntax: SyntaxNode, | ||
1256 | } | ||
1257 | unsafe impl TransparentNewType for FloatNumber { | ||
1258 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1259 | } | ||
1260 | |||
1261 | impl AstNode for FloatNumber { | ||
1262 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1263 | match syntax.kind() { | ||
1264 | FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())), | ||
1265 | _ => None, | ||
1266 | } | ||
1267 | } | ||
1268 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1269 | } | ||
1270 | |||
1271 | impl ToOwned for FloatNumber { | ||
1272 | type Owned = TreeArc<FloatNumber>; | ||
1273 | fn to_owned(&self) -> TreeArc<FloatNumber> { TreeArc::cast(self.syntax.to_owned()) } | ||
1274 | } | ||
1275 | |||
1276 | |||
1277 | impl ast::AstToken for FloatNumber {} | ||
1278 | impl FloatNumber {} | ||
1279 | |||
1280 | // FnDef | 1119 | // FnDef |
1281 | #[derive(Debug, PartialEq, Eq, Hash)] | 1120 | #[derive(Debug, PartialEq, Eq, Hash)] |
1282 | #[repr(transparent)] | 1121 | #[repr(transparent)] |
@@ -1581,6 +1420,7 @@ impl ToOwned for ImplTraitType { | |||
1581 | } | 1420 | } |
1582 | 1421 | ||
1583 | 1422 | ||
1423 | impl ast::TypeBoundsOwner for ImplTraitType {} | ||
1584 | impl ImplTraitType {} | 1424 | impl ImplTraitType {} |
1585 | 1425 | ||
1586 | // IndexExpr | 1426 | // IndexExpr |
@@ -1611,35 +1451,6 @@ impl ToOwned for IndexExpr { | |||
1611 | 1451 | ||
1612 | impl IndexExpr {} | 1452 | impl IndexExpr {} |
1613 | 1453 | ||
1614 | // IntNumber | ||
1615 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1616 | #[repr(transparent)] | ||
1617 | pub struct IntNumber { | ||
1618 | pub(crate) syntax: SyntaxNode, | ||
1619 | } | ||
1620 | unsafe impl TransparentNewType for IntNumber { | ||
1621 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1622 | } | ||
1623 | |||
1624 | impl AstNode for IntNumber { | ||
1625 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1626 | match syntax.kind() { | ||
1627 | INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())), | ||
1628 | _ => None, | ||
1629 | } | ||
1630 | } | ||
1631 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1632 | } | ||
1633 | |||
1634 | impl ToOwned for IntNumber { | ||
1635 | type Owned = TreeArc<IntNumber>; | ||
1636 | fn to_owned(&self) -> TreeArc<IntNumber> { TreeArc::cast(self.syntax.to_owned()) } | ||
1637 | } | ||
1638 | |||
1639 | |||
1640 | impl ast::AstToken for IntNumber {} | ||
1641 | impl IntNumber {} | ||
1642 | |||
1643 | // ItemList | 1454 | // ItemList |
1644 | #[derive(Debug, PartialEq, Eq, Hash)] | 1455 | #[derive(Debug, PartialEq, Eq, Hash)] |
1645 | #[repr(transparent)] | 1456 | #[repr(transparent)] |
@@ -1775,35 +1586,6 @@ impl LetStmt { | |||
1775 | } | 1586 | } |
1776 | } | 1587 | } |
1777 | 1588 | ||
1778 | // Lifetime | ||
1779 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1780 | #[repr(transparent)] | ||
1781 | pub struct Lifetime { | ||
1782 | pub(crate) syntax: SyntaxNode, | ||
1783 | } | ||
1784 | unsafe impl TransparentNewType for Lifetime { | ||
1785 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1786 | } | ||
1787 | |||
1788 | impl AstNode for Lifetime { | ||
1789 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1790 | match syntax.kind() { | ||
1791 | LIFETIME => Some(Lifetime::from_repr(syntax.into_repr())), | ||
1792 | _ => None, | ||
1793 | } | ||
1794 | } | ||
1795 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1796 | } | ||
1797 | |||
1798 | impl ToOwned for Lifetime { | ||
1799 | type Owned = TreeArc<Lifetime>; | ||
1800 | fn to_owned(&self) -> TreeArc<Lifetime> { TreeArc::cast(self.syntax.to_owned()) } | ||
1801 | } | ||
1802 | |||
1803 | |||
1804 | impl ast::AstToken for Lifetime {} | ||
1805 | impl Lifetime {} | ||
1806 | |||
1807 | // LifetimeArg | 1589 | // LifetimeArg |
1808 | #[derive(Debug, PartialEq, Eq, Hash)] | 1590 | #[derive(Debug, PartialEq, Eq, Hash)] |
1809 | #[repr(transparent)] | 1591 | #[repr(transparent)] |
@@ -1830,11 +1612,7 @@ impl ToOwned for LifetimeArg { | |||
1830 | } | 1612 | } |
1831 | 1613 | ||
1832 | 1614 | ||
1833 | impl LifetimeArg { | 1615 | impl LifetimeArg {} |
1834 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1835 | super::child_opt(self) | ||
1836 | } | ||
1837 | } | ||
1838 | 1616 | ||
1839 | // LifetimeParam | 1617 | // LifetimeParam |
1840 | #[derive(Debug, PartialEq, Eq, Hash)] | 1618 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -1863,11 +1641,7 @@ impl ToOwned for LifetimeParam { | |||
1863 | 1641 | ||
1864 | 1642 | ||
1865 | impl ast::AttrsOwner for LifetimeParam {} | 1643 | impl ast::AttrsOwner for LifetimeParam {} |
1866 | impl LifetimeParam { | 1644 | impl LifetimeParam {} |
1867 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1868 | super::child_opt(self) | ||
1869 | } | ||
1870 | } | ||
1871 | 1645 | ||
1872 | // Literal | 1646 | // Literal |
1873 | #[derive(Debug, PartialEq, Eq, Hash)] | 1647 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -1895,130 +1669,7 @@ impl ToOwned for Literal { | |||
1895 | } | 1669 | } |
1896 | 1670 | ||
1897 | 1671 | ||
1898 | impl Literal { | 1672 | impl Literal {} |
1899 | pub fn literal_expr(&self) -> Option<&LiteralExpr> { | ||
1900 | super::child_opt(self) | ||
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | // LiteralExpr | ||
1905 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1906 | #[repr(transparent)] | ||
1907 | pub struct LiteralExpr { | ||
1908 | pub(crate) syntax: SyntaxNode, | ||
1909 | } | ||
1910 | unsafe impl TransparentNewType for LiteralExpr { | ||
1911 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1912 | } | ||
1913 | |||
1914 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
1915 | pub enum LiteralExprKind<'a> { | ||
1916 | String(&'a String), | ||
1917 | ByteString(&'a ByteString), | ||
1918 | RawString(&'a RawString), | ||
1919 | RawByteString(&'a RawByteString), | ||
1920 | Char(&'a Char), | ||
1921 | Byte(&'a Byte), | ||
1922 | IntNumber(&'a IntNumber), | ||
1923 | FloatNumber(&'a FloatNumber), | ||
1924 | TrueKw(&'a TrueKw), | ||
1925 | FalseKw(&'a FalseKw), | ||
1926 | } | ||
1927 | impl<'a> From<&'a String> for &'a LiteralExpr { | ||
1928 | fn from(n: &'a String) -> &'a LiteralExpr { | ||
1929 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1930 | } | ||
1931 | } | ||
1932 | impl<'a> From<&'a ByteString> for &'a LiteralExpr { | ||
1933 | fn from(n: &'a ByteString) -> &'a LiteralExpr { | ||
1934 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1935 | } | ||
1936 | } | ||
1937 | impl<'a> From<&'a RawString> for &'a LiteralExpr { | ||
1938 | fn from(n: &'a RawString) -> &'a LiteralExpr { | ||
1939 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1940 | } | ||
1941 | } | ||
1942 | impl<'a> From<&'a RawByteString> for &'a LiteralExpr { | ||
1943 | fn from(n: &'a RawByteString) -> &'a LiteralExpr { | ||
1944 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1945 | } | ||
1946 | } | ||
1947 | impl<'a> From<&'a Char> for &'a LiteralExpr { | ||
1948 | fn from(n: &'a Char) -> &'a LiteralExpr { | ||
1949 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1950 | } | ||
1951 | } | ||
1952 | impl<'a> From<&'a Byte> for &'a LiteralExpr { | ||
1953 | fn from(n: &'a Byte) -> &'a LiteralExpr { | ||
1954 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1955 | } | ||
1956 | } | ||
1957 | impl<'a> From<&'a IntNumber> for &'a LiteralExpr { | ||
1958 | fn from(n: &'a IntNumber) -> &'a LiteralExpr { | ||
1959 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1960 | } | ||
1961 | } | ||
1962 | impl<'a> From<&'a FloatNumber> for &'a LiteralExpr { | ||
1963 | fn from(n: &'a FloatNumber) -> &'a LiteralExpr { | ||
1964 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1965 | } | ||
1966 | } | ||
1967 | impl<'a> From<&'a TrueKw> for &'a LiteralExpr { | ||
1968 | fn from(n: &'a TrueKw) -> &'a LiteralExpr { | ||
1969 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1970 | } | ||
1971 | } | ||
1972 | impl<'a> From<&'a FalseKw> for &'a LiteralExpr { | ||
1973 | fn from(n: &'a FalseKw) -> &'a LiteralExpr { | ||
1974 | LiteralExpr::cast(&n.syntax).unwrap() | ||
1975 | } | ||
1976 | } | ||
1977 | |||
1978 | |||
1979 | impl AstNode for LiteralExpr { | ||
1980 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1981 | match syntax.kind() { | ||
1982 | | STRING | ||
1983 | | BYTE_STRING | ||
1984 | | RAW_STRING | ||
1985 | | RAW_BYTE_STRING | ||
1986 | | CHAR | ||
1987 | | BYTE | ||
1988 | | INT_NUMBER | ||
1989 | | FLOAT_NUMBER | ||
1990 | | TRUE_KW | ||
1991 | | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())), | ||
1992 | _ => None, | ||
1993 | } | ||
1994 | } | ||
1995 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1996 | } | ||
1997 | |||
1998 | impl ToOwned for LiteralExpr { | ||
1999 | type Owned = TreeArc<LiteralExpr>; | ||
2000 | fn to_owned(&self) -> TreeArc<LiteralExpr> { TreeArc::cast(self.syntax.to_owned()) } | ||
2001 | } | ||
2002 | |||
2003 | impl LiteralExpr { | ||
2004 | pub fn kind(&self) -> LiteralExprKind { | ||
2005 | match self.syntax.kind() { | ||
2006 | STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()), | ||
2007 | BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()), | ||
2008 | RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()), | ||
2009 | RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()), | ||
2010 | CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()), | ||
2011 | BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()), | ||
2012 | INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), | ||
2013 | FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), | ||
2014 | TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()), | ||
2015 | FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()), | ||
2016 | _ => unreachable!(), | ||
2017 | } | ||
2018 | } | ||
2019 | } | ||
2020 | |||
2021 | impl LiteralExpr {} | ||
2022 | 1673 | ||
2023 | // LiteralPat | 1674 | // LiteralPat |
2024 | #[derive(Debug, PartialEq, Eq, Hash)] | 1675 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3402,64 +3053,6 @@ impl ToOwned for RangePat { | |||
3402 | 3053 | ||
3403 | impl RangePat {} | 3054 | impl RangePat {} |
3404 | 3055 | ||
3405 | // RawByteString | ||
3406 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3407 | #[repr(transparent)] | ||
3408 | pub struct RawByteString { | ||
3409 | pub(crate) syntax: SyntaxNode, | ||
3410 | } | ||
3411 | unsafe impl TransparentNewType for RawByteString { | ||
3412 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3413 | } | ||
3414 | |||
3415 | impl AstNode for RawByteString { | ||
3416 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3417 | match syntax.kind() { | ||
3418 | RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())), | ||
3419 | _ => None, | ||
3420 | } | ||
3421 | } | ||
3422 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3423 | } | ||
3424 | |||
3425 | impl ToOwned for RawByteString { | ||
3426 | type Owned = TreeArc<RawByteString>; | ||
3427 | fn to_owned(&self) -> TreeArc<RawByteString> { TreeArc::cast(self.syntax.to_owned()) } | ||
3428 | } | ||
3429 | |||
3430 | |||
3431 | impl ast::AstToken for RawByteString {} | ||
3432 | impl RawByteString {} | ||
3433 | |||
3434 | // RawString | ||
3435 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3436 | #[repr(transparent)] | ||
3437 | pub struct RawString { | ||
3438 | pub(crate) syntax: SyntaxNode, | ||
3439 | } | ||
3440 | unsafe impl TransparentNewType for RawString { | ||
3441 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3442 | } | ||
3443 | |||
3444 | impl AstNode for RawString { | ||
3445 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3446 | match syntax.kind() { | ||
3447 | RAW_STRING => Some(RawString::from_repr(syntax.into_repr())), | ||
3448 | _ => None, | ||
3449 | } | ||
3450 | } | ||
3451 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3452 | } | ||
3453 | |||
3454 | impl ToOwned for RawString { | ||
3455 | type Owned = TreeArc<RawString>; | ||
3456 | fn to_owned(&self) -> TreeArc<RawString> { TreeArc::cast(self.syntax.to_owned()) } | ||
3457 | } | ||
3458 | |||
3459 | |||
3460 | impl ast::AstToken for RawString {} | ||
3461 | impl RawString {} | ||
3462 | |||
3463 | // RefExpr | 3056 | // RefExpr |
3464 | #[derive(Debug, PartialEq, Eq, Hash)] | 3057 | #[derive(Debug, PartialEq, Eq, Hash)] |
3465 | #[repr(transparent)] | 3058 | #[repr(transparent)] |
@@ -3620,34 +3213,6 @@ impl ReturnExpr { | |||
3620 | } | 3213 | } |
3621 | } | 3214 | } |
3622 | 3215 | ||
3623 | // SelfKw | ||
3624 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3625 | #[repr(transparent)] | ||
3626 | pub struct SelfKw { | ||
3627 | pub(crate) syntax: SyntaxNode, | ||
3628 | } | ||
3629 | unsafe impl TransparentNewType for SelfKw { | ||
3630 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3631 | } | ||
3632 | |||
3633 | impl AstNode for SelfKw { | ||
3634 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3635 | match syntax.kind() { | ||
3636 | SELF_KW => Some(SelfKw::from_repr(syntax.into_repr())), | ||
3637 | _ => None, | ||
3638 | } | ||
3639 | } | ||
3640 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3641 | } | ||
3642 | |||
3643 | impl ToOwned for SelfKw { | ||
3644 | type Owned = TreeArc<SelfKw>; | ||
3645 | fn to_owned(&self) -> TreeArc<SelfKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
3646 | } | ||
3647 | |||
3648 | |||
3649 | impl SelfKw {} | ||
3650 | |||
3651 | // SelfParam | 3216 | // SelfParam |
3652 | #[derive(Debug, PartialEq, Eq, Hash)] | 3217 | #[derive(Debug, PartialEq, Eq, Hash)] |
3653 | #[repr(transparent)] | 3218 | #[repr(transparent)] |
@@ -3675,11 +3240,7 @@ impl ToOwned for SelfParam { | |||
3675 | 3240 | ||
3676 | 3241 | ||
3677 | impl ast::TypeAscriptionOwner for SelfParam {} | 3242 | impl ast::TypeAscriptionOwner for SelfParam {} |
3678 | impl SelfParam { | 3243 | impl SelfParam {} |
3679 | pub fn self_kw(&self) -> Option<&SelfKw> { | ||
3680 | super::child_opt(self) | ||
3681 | } | ||
3682 | } | ||
3683 | 3244 | ||
3684 | // SlicePat | 3245 | // SlicePat |
3685 | #[derive(Debug, PartialEq, Eq, Hash)] | 3246 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3807,7 +3368,11 @@ impl ast::TypeParamsOwner for StaticDef {} | |||
3807 | impl ast::AttrsOwner for StaticDef {} | 3368 | impl ast::AttrsOwner for StaticDef {} |
3808 | impl ast::DocCommentsOwner for StaticDef {} | 3369 | impl ast::DocCommentsOwner for StaticDef {} |
3809 | impl ast::TypeAscriptionOwner for StaticDef {} | 3370 | impl ast::TypeAscriptionOwner for StaticDef {} |
3810 | impl StaticDef {} | 3371 | impl StaticDef { |
3372 | pub fn body(&self) -> Option<&Expr> { | ||
3373 | super::child_opt(self) | ||
3374 | } | ||
3375 | } | ||
3811 | 3376 | ||
3812 | // Stmt | 3377 | // Stmt |
3813 | #[derive(Debug, PartialEq, Eq, Hash)] | 3378 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3864,35 +3429,6 @@ impl Stmt { | |||
3864 | 3429 | ||
3865 | impl Stmt {} | 3430 | impl Stmt {} |
3866 | 3431 | ||
3867 | // String | ||
3868 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3869 | #[repr(transparent)] | ||
3870 | pub struct String { | ||
3871 | pub(crate) syntax: SyntaxNode, | ||
3872 | } | ||
3873 | unsafe impl TransparentNewType for String { | ||
3874 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3875 | } | ||
3876 | |||
3877 | impl AstNode for String { | ||
3878 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3879 | match syntax.kind() { | ||
3880 | STRING => Some(String::from_repr(syntax.into_repr())), | ||
3881 | _ => None, | ||
3882 | } | ||
3883 | } | ||
3884 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3885 | } | ||
3886 | |||
3887 | impl ToOwned for String { | ||
3888 | type Owned = TreeArc<String>; | ||
3889 | fn to_owned(&self) -> TreeArc<String> { TreeArc::cast(self.syntax.to_owned()) } | ||
3890 | } | ||
3891 | |||
3892 | |||
3893 | impl ast::AstToken for String {} | ||
3894 | impl String {} | ||
3895 | |||
3896 | // StructDef | 3432 | // StructDef |
3897 | #[derive(Debug, PartialEq, Eq, Hash)] | 3433 | #[derive(Debug, PartialEq, Eq, Hash)] |
3898 | #[repr(transparent)] | 3434 | #[repr(transparent)] |
@@ -4061,41 +3597,13 @@ impl ast::NameOwner for TraitDef {} | |||
4061 | impl ast::AttrsOwner for TraitDef {} | 3597 | impl ast::AttrsOwner for TraitDef {} |
4062 | impl ast::DocCommentsOwner for TraitDef {} | 3598 | impl ast::DocCommentsOwner for TraitDef {} |
4063 | impl ast::TypeParamsOwner for TraitDef {} | 3599 | impl ast::TypeParamsOwner for TraitDef {} |
3600 | impl ast::TypeBoundsOwner for TraitDef {} | ||
4064 | impl TraitDef { | 3601 | impl TraitDef { |
4065 | pub fn item_list(&self) -> Option<&ItemList> { | 3602 | pub fn item_list(&self) -> Option<&ItemList> { |
4066 | super::child_opt(self) | 3603 | super::child_opt(self) |
4067 | } | 3604 | } |
4068 | } | 3605 | } |
4069 | 3606 | ||
4070 | // TrueKw | ||
4071 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
4072 | #[repr(transparent)] | ||
4073 | pub struct TrueKw { | ||
4074 | pub(crate) syntax: SyntaxNode, | ||
4075 | } | ||
4076 | unsafe impl TransparentNewType for TrueKw { | ||
4077 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
4078 | } | ||
4079 | |||
4080 | impl AstNode for TrueKw { | ||
4081 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
4082 | match syntax.kind() { | ||
4083 | TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())), | ||
4084 | _ => None, | ||
4085 | } | ||
4086 | } | ||
4087 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
4088 | } | ||
4089 | |||
4090 | impl ToOwned for TrueKw { | ||
4091 | type Owned = TreeArc<TrueKw>; | ||
4092 | fn to_owned(&self) -> TreeArc<TrueKw> { TreeArc::cast(self.syntax.to_owned()) } | ||
4093 | } | ||
4094 | |||
4095 | |||
4096 | impl ast::AstToken for TrueKw {} | ||
4097 | impl TrueKw {} | ||
4098 | |||
4099 | // TryExpr | 3607 | // TryExpr |
4100 | #[derive(Debug, PartialEq, Eq, Hash)] | 3608 | #[derive(Debug, PartialEq, Eq, Hash)] |
4101 | #[repr(transparent)] | 3609 | #[repr(transparent)] |
@@ -4291,6 +3799,7 @@ impl ast::NameOwner for TypeAliasDef {} | |||
4291 | impl ast::TypeParamsOwner for TypeAliasDef {} | 3799 | impl ast::TypeParamsOwner for TypeAliasDef {} |
4292 | impl ast::AttrsOwner for TypeAliasDef {} | 3800 | impl ast::AttrsOwner for TypeAliasDef {} |
4293 | impl ast::DocCommentsOwner for TypeAliasDef {} | 3801 | impl ast::DocCommentsOwner for TypeAliasDef {} |
3802 | impl ast::TypeBoundsOwner for TypeAliasDef {} | ||
4294 | impl TypeAliasDef { | 3803 | impl TypeAliasDef { |
4295 | pub fn type_ref(&self) -> Option<&TypeRef> { | 3804 | pub fn type_ref(&self) -> Option<&TypeRef> { |
4296 | super::child_opt(self) | 3805 | super::child_opt(self) |
@@ -4369,6 +3878,70 @@ impl TypeArgList { | |||
4369 | } | 3878 | } |
4370 | } | 3879 | } |
4371 | 3880 | ||
3881 | // TypeBound | ||
3882 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3883 | #[repr(transparent)] | ||
3884 | pub struct TypeBound { | ||
3885 | pub(crate) syntax: SyntaxNode, | ||
3886 | } | ||
3887 | unsafe impl TransparentNewType for TypeBound { | ||
3888 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3889 | } | ||
3890 | |||
3891 | impl AstNode for TypeBound { | ||
3892 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3893 | match syntax.kind() { | ||
3894 | TYPE_BOUND => Some(TypeBound::from_repr(syntax.into_repr())), | ||
3895 | _ => None, | ||
3896 | } | ||
3897 | } | ||
3898 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3899 | } | ||
3900 | |||
3901 | impl ToOwned for TypeBound { | ||
3902 | type Owned = TreeArc<TypeBound>; | ||
3903 | fn to_owned(&self) -> TreeArc<TypeBound> { TreeArc::cast(self.syntax.to_owned()) } | ||
3904 | } | ||
3905 | |||
3906 | |||
3907 | impl TypeBound { | ||
3908 | pub fn type_ref(&self) -> Option<&TypeRef> { | ||
3909 | super::child_opt(self) | ||
3910 | } | ||
3911 | } | ||
3912 | |||
3913 | // TypeBoundList | ||
3914 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3915 | #[repr(transparent)] | ||
3916 | pub struct TypeBoundList { | ||
3917 | pub(crate) syntax: SyntaxNode, | ||
3918 | } | ||
3919 | unsafe impl TransparentNewType for TypeBoundList { | ||
3920 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3921 | } | ||
3922 | |||
3923 | impl AstNode for TypeBoundList { | ||
3924 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3925 | match syntax.kind() { | ||
3926 | TYPE_BOUND_LIST => Some(TypeBoundList::from_repr(syntax.into_repr())), | ||
3927 | _ => None, | ||
3928 | } | ||
3929 | } | ||
3930 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3931 | } | ||
3932 | |||
3933 | impl ToOwned for TypeBoundList { | ||
3934 | type Owned = TreeArc<TypeBoundList>; | ||
3935 | fn to_owned(&self) -> TreeArc<TypeBoundList> { TreeArc::cast(self.syntax.to_owned()) } | ||
3936 | } | ||
3937 | |||
3938 | |||
3939 | impl TypeBoundList { | ||
3940 | pub fn bounds(&self) -> impl Iterator<Item = &TypeBound> { | ||
3941 | super::children(self) | ||
3942 | } | ||
3943 | } | ||
3944 | |||
4372 | // TypeParam | 3945 | // TypeParam |
4373 | #[derive(Debug, PartialEq, Eq, Hash)] | 3946 | #[derive(Debug, PartialEq, Eq, Hash)] |
4374 | #[repr(transparent)] | 3947 | #[repr(transparent)] |
@@ -4397,6 +3970,7 @@ impl ToOwned for TypeParam { | |||
4397 | 3970 | ||
4398 | impl ast::NameOwner for TypeParam {} | 3971 | impl ast::NameOwner for TypeParam {} |
4399 | impl ast::AttrsOwner for TypeParam {} | 3972 | impl ast::AttrsOwner for TypeParam {} |
3973 | impl ast::TypeBoundsOwner for TypeParam {} | ||
4400 | impl TypeParam {} | 3974 | impl TypeParam {} |
4401 | 3975 | ||
4402 | // TypeParamList | 3976 | // TypeParamList |
@@ -4737,67 +4311,75 @@ impl ToOwned for WhereClause { | |||
4737 | } | 4311 | } |
4738 | 4312 | ||
4739 | 4313 | ||
4740 | impl WhereClause {} | 4314 | impl WhereClause { |
4315 | pub fn predicates(&self) -> impl Iterator<Item = &WherePred> { | ||
4316 | super::children(self) | ||
4317 | } | ||
4318 | } | ||
4741 | 4319 | ||
4742 | // WhileExpr | 4320 | // WherePred |
4743 | #[derive(Debug, PartialEq, Eq, Hash)] | 4321 | #[derive(Debug, PartialEq, Eq, Hash)] |
4744 | #[repr(transparent)] | 4322 | #[repr(transparent)] |
4745 | pub struct WhileExpr { | 4323 | pub struct WherePred { |
4746 | pub(crate) syntax: SyntaxNode, | 4324 | pub(crate) syntax: SyntaxNode, |
4747 | } | 4325 | } |
4748 | unsafe impl TransparentNewType for WhileExpr { | 4326 | unsafe impl TransparentNewType for WherePred { |
4749 | type Repr = rowan::SyntaxNode<RaTypes>; | 4327 | type Repr = rowan::SyntaxNode<RaTypes>; |
4750 | } | 4328 | } |
4751 | 4329 | ||
4752 | impl AstNode for WhileExpr { | 4330 | impl AstNode for WherePred { |
4753 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | 4331 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { |
4754 | match syntax.kind() { | 4332 | match syntax.kind() { |
4755 | WHILE_EXPR => Some(WhileExpr::from_repr(syntax.into_repr())), | 4333 | WHERE_PRED => Some(WherePred::from_repr(syntax.into_repr())), |
4756 | _ => None, | 4334 | _ => None, |
4757 | } | 4335 | } |
4758 | } | 4336 | } |
4759 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 4337 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
4760 | } | 4338 | } |
4761 | 4339 | ||
4762 | impl ToOwned for WhileExpr { | 4340 | impl ToOwned for WherePred { |
4763 | type Owned = TreeArc<WhileExpr>; | 4341 | type Owned = TreeArc<WherePred>; |
4764 | fn to_owned(&self) -> TreeArc<WhileExpr> { TreeArc::cast(self.syntax.to_owned()) } | 4342 | fn to_owned(&self) -> TreeArc<WherePred> { TreeArc::cast(self.syntax.to_owned()) } |
4765 | } | 4343 | } |
4766 | 4344 | ||
4767 | 4345 | ||
4768 | impl ast::LoopBodyOwner for WhileExpr {} | 4346 | impl ast::TypeBoundsOwner for WherePred {} |
4769 | impl WhileExpr { | 4347 | impl WherePred { |
4770 | pub fn condition(&self) -> Option<&Condition> { | 4348 | pub fn type_ref(&self) -> Option<&TypeRef> { |
4771 | super::child_opt(self) | 4349 | super::child_opt(self) |
4772 | } | 4350 | } |
4773 | } | 4351 | } |
4774 | 4352 | ||
4775 | // Whitespace | 4353 | // WhileExpr |
4776 | #[derive(Debug, PartialEq, Eq, Hash)] | 4354 | #[derive(Debug, PartialEq, Eq, Hash)] |
4777 | #[repr(transparent)] | 4355 | #[repr(transparent)] |
4778 | pub struct Whitespace { | 4356 | pub struct WhileExpr { |
4779 | pub(crate) syntax: SyntaxNode, | 4357 | pub(crate) syntax: SyntaxNode, |
4780 | } | 4358 | } |
4781 | unsafe impl TransparentNewType for Whitespace { | 4359 | unsafe impl TransparentNewType for WhileExpr { |
4782 | type Repr = rowan::SyntaxNode<RaTypes>; | 4360 | type Repr = rowan::SyntaxNode<RaTypes>; |
4783 | } | 4361 | } |
4784 | 4362 | ||
4785 | impl AstNode for Whitespace { | 4363 | impl AstNode for WhileExpr { |
4786 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | 4364 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { |
4787 | match syntax.kind() { | 4365 | match syntax.kind() { |
4788 | WHITESPACE => Some(Whitespace::from_repr(syntax.into_repr())), | 4366 | WHILE_EXPR => Some(WhileExpr::from_repr(syntax.into_repr())), |
4789 | _ => None, | 4367 | _ => None, |
4790 | } | 4368 | } |
4791 | } | 4369 | } |
4792 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | 4370 | fn syntax(&self) -> &SyntaxNode { &self.syntax } |
4793 | } | 4371 | } |
4794 | 4372 | ||
4795 | impl ToOwned for Whitespace { | 4373 | impl ToOwned for WhileExpr { |
4796 | type Owned = TreeArc<Whitespace>; | 4374 | type Owned = TreeArc<WhileExpr>; |
4797 | fn to_owned(&self) -> TreeArc<Whitespace> { TreeArc::cast(self.syntax.to_owned()) } | 4375 | fn to_owned(&self) -> TreeArc<WhileExpr> { TreeArc::cast(self.syntax.to_owned()) } |
4798 | } | 4376 | } |
4799 | 4377 | ||
4800 | 4378 | ||
4801 | impl ast::AstToken for Whitespace {} | 4379 | impl ast::LoopBodyOwner for WhileExpr {} |
4802 | impl Whitespace {} | 4380 | impl WhileExpr { |
4381 | pub fn condition(&self) -> Option<&Condition> { | ||
4382 | super::child_opt(self) | ||
4383 | } | ||
4384 | } | ||
4803 | 4385 | ||
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs new file mode 100644 index 000000000..08882ea69 --- /dev/null +++ b/crates/ra_syntax/src/ast/tokens.rs | |||
@@ -0,0 +1,113 @@ | |||
1 | //! There are many AstNodes, but only a few tokens, so we hand-write them here. | ||
2 | |||
3 | use crate::{ | ||
4 | SyntaxToken, | ||
5 | SyntaxKind::{COMMENT, WHITESPACE}, | ||
6 | ast::AstToken, | ||
7 | }; | ||
8 | |||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
10 | pub struct Comment<'a>(SyntaxToken<'a>); | ||
11 | |||
12 | impl<'a> AstToken<'a> for Comment<'a> { | ||
13 | fn cast(token: SyntaxToken<'a>) -> Option<Self> { | ||
14 | if token.kind() == COMMENT { | ||
15 | Some(Comment(token)) | ||
16 | } else { | ||
17 | None | ||
18 | } | ||
19 | } | ||
20 | fn syntax(&self) -> SyntaxToken<'a> { | ||
21 | self.0 | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl<'a> Comment<'a> { | ||
26 | pub fn kind(&self) -> CommentKind { | ||
27 | kind_by_prefix(self.text()) | ||
28 | } | ||
29 | |||
30 | pub fn prefix(&self) -> &'static str { | ||
31 | prefix_by_kind(self.kind()) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
36 | pub struct CommentKind { | ||
37 | pub shape: CommentShape, | ||
38 | pub doc: Option<CommentPlacement>, | ||
39 | } | ||
40 | |||
41 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
42 | pub enum CommentShape { | ||
43 | Line, | ||
44 | Block, | ||
45 | } | ||
46 | |||
47 | impl CommentShape { | ||
48 | pub fn is_line(self) -> bool { | ||
49 | self == CommentShape::Line | ||
50 | } | ||
51 | |||
52 | pub fn is_block(self) -> bool { | ||
53 | self == CommentShape::Block | ||
54 | } | ||
55 | } | ||
56 | |||
57 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
58 | pub enum CommentPlacement { | ||
59 | Inner, | ||
60 | Outer, | ||
61 | } | ||
62 | |||
63 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { | ||
64 | use {CommentShape::*, CommentPlacement::*}; | ||
65 | &[ | ||
66 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), | ||
67 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), | ||
68 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), | ||
69 | ("/*!", CommentKind { shape: Block, doc: Some(Inner) }), | ||
70 | ("//", CommentKind { shape: Line, doc: None }), | ||
71 | ("/*", CommentKind { shape: Block, doc: None }), | ||
72 | ] | ||
73 | }; | ||
74 | |||
75 | fn kind_by_prefix(text: &str) -> CommentKind { | ||
76 | for (prefix, kind) in COMMENT_PREFIX_TO_KIND.iter() { | ||
77 | if text.starts_with(prefix) { | ||
78 | return *kind; | ||
79 | } | ||
80 | } | ||
81 | panic!("bad comment text: {:?}", text) | ||
82 | } | ||
83 | |||
84 | fn prefix_by_kind(kind: CommentKind) -> &'static str { | ||
85 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { | ||
86 | if *k == kind { | ||
87 | return prefix; | ||
88 | } | ||
89 | } | ||
90 | unreachable!() | ||
91 | } | ||
92 | |||
93 | pub struct Whitespace<'a>(SyntaxToken<'a>); | ||
94 | |||
95 | impl<'a> AstToken<'a> for Whitespace<'a> { | ||
96 | fn cast(token: SyntaxToken<'a>) -> Option<Self> { | ||
97 | if token.kind() == WHITESPACE { | ||
98 | Some(Whitespace(token)) | ||
99 | } else { | ||
100 | None | ||
101 | } | ||
102 | } | ||
103 | fn syntax(&self) -> SyntaxToken<'a> { | ||
104 | self.0 | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl<'a> Whitespace<'a> { | ||
109 | pub fn spans_multiple_lines(&self) -> bool { | ||
110 | let text = self.text(); | ||
111 | text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) | ||
112 | } | ||
113 | } | ||
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs new file mode 100644 index 000000000..aaf07d731 --- /dev/null +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -0,0 +1,154 @@ | |||
1 | //! Various traits that are implemented by ast nodes. | ||
2 | //! | ||
3 | //! The implementations are usually trivial, and live in generated.rs | ||
4 | |||
5 | use itertools::Itertools; | ||
6 | |||
7 | use crate::{ | ||
8 | syntax_node::{SyntaxNodeChildren, SyntaxElementChildren}, | ||
9 | ast::{self, child_opt, children, AstNode, AstToken, AstChildren}, | ||
10 | }; | ||
11 | |||
12 | pub trait TypeAscriptionOwner: AstNode { | ||
13 | fn ascribed_type(&self) -> Option<&ast::TypeRef> { | ||
14 | child_opt(self) | ||
15 | } | ||
16 | } | ||
17 | |||
18 | pub trait NameOwner: AstNode { | ||
19 | fn name(&self) -> Option<&ast::Name> { | ||
20 | child_opt(self) | ||
21 | } | ||
22 | } | ||
23 | |||
24 | pub trait VisibilityOwner: AstNode { | ||
25 | fn visibility(&self) -> Option<&ast::Visibility> { | ||
26 | child_opt(self) | ||
27 | } | ||
28 | } | ||
29 | |||
30 | pub trait LoopBodyOwner: AstNode { | ||
31 | fn loop_body(&self) -> Option<&ast::Block> { | ||
32 | child_opt(self) | ||
33 | } | ||
34 | } | ||
35 | |||
36 | pub trait ArgListOwner: AstNode { | ||
37 | fn arg_list(&self) -> Option<&ast::ArgList> { | ||
38 | child_opt(self) | ||
39 | } | ||
40 | } | ||
41 | |||
42 | pub trait FnDefOwner: AstNode { | ||
43 | fn functions(&self) -> AstChildren<ast::FnDef> { | ||
44 | children(self) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
49 | pub enum ItemOrMacro<'a> { | ||
50 | Item(&'a ast::ModuleItem), | ||
51 | Macro(&'a ast::MacroCall), | ||
52 | } | ||
53 | |||
54 | pub trait ModuleItemOwner: AstNode { | ||
55 | fn items(&self) -> AstChildren<ast::ModuleItem> { | ||
56 | children(self) | ||
57 | } | ||
58 | fn items_with_macros(&self) -> ItemOrMacroIter { | ||
59 | ItemOrMacroIter(self.syntax().children()) | ||
60 | } | ||
61 | } | ||
62 | |||
63 | #[derive(Debug)] | ||
64 | pub struct ItemOrMacroIter<'a>(SyntaxNodeChildren<'a>); | ||
65 | |||
66 | impl<'a> Iterator for ItemOrMacroIter<'a> { | ||
67 | type Item = ItemOrMacro<'a>; | ||
68 | fn next(&mut self) -> Option<ItemOrMacro<'a>> { | ||
69 | loop { | ||
70 | let n = self.0.next()?; | ||
71 | if let Some(item) = ast::ModuleItem::cast(n) { | ||
72 | return Some(ItemOrMacro::Item(item)); | ||
73 | } | ||
74 | if let Some(call) = ast::MacroCall::cast(n) { | ||
75 | return Some(ItemOrMacro::Macro(call)); | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | pub trait TypeParamsOwner: AstNode { | ||
82 | fn type_param_list(&self) -> Option<&ast::TypeParamList> { | ||
83 | child_opt(self) | ||
84 | } | ||
85 | |||
86 | fn where_clause(&self) -> Option<&ast::WhereClause> { | ||
87 | child_opt(self) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | pub trait TypeBoundsOwner: AstNode { | ||
92 | fn type_bound_list(&self) -> Option<&ast::TypeBoundList> { | ||
93 | child_opt(self) | ||
94 | } | ||
95 | } | ||
96 | |||
97 | pub trait AttrsOwner: AstNode { | ||
98 | fn attrs(&self) -> AstChildren<ast::Attr> { | ||
99 | children(self) | ||
100 | } | ||
101 | fn has_atom_attr(&self, atom: &str) -> bool { | ||
102 | self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) | ||
103 | } | ||
104 | } | ||
105 | |||
106 | pub trait DocCommentsOwner: AstNode { | ||
107 | fn doc_comments(&self) -> CommentIter { | ||
108 | CommentIter { iter: self.syntax().children_with_tokens() } | ||
109 | } | ||
110 | |||
111 | /// Returns the textual content of a doc comment block as a single string. | ||
112 | /// That is, strips leading `///` (+ optional 1 character of whitespace) | ||
113 | /// and joins lines. | ||
114 | fn doc_comment_text(&self) -> Option<String> { | ||
115 | let mut has_comments = false; | ||
116 | let docs = self | ||
117 | .doc_comments() | ||
118 | .filter(|comment| comment.kind().doc.is_some()) | ||
119 | .map(|comment| { | ||
120 | has_comments = true; | ||
121 | let prefix_len = comment.prefix().len(); | ||
122 | |||
123 | let line = comment.text().as_str(); | ||
124 | |||
125 | // Determine if the prefix or prefix + 1 char is stripped | ||
126 | let pos = | ||
127 | if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) { | ||
128 | prefix_len + 1 | ||
129 | } else { | ||
130 | prefix_len | ||
131 | }; | ||
132 | |||
133 | line[pos..].to_owned() | ||
134 | }) | ||
135 | .join("\n"); | ||
136 | |||
137 | if has_comments { | ||
138 | Some(docs) | ||
139 | } else { | ||
140 | None | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | pub struct CommentIter<'a> { | ||
146 | iter: SyntaxElementChildren<'a>, | ||
147 | } | ||
148 | |||
149 | impl<'a> Iterator for CommentIter<'a> { | ||
150 | type Item = ast::Comment<'a>; | ||
151 | fn next(&mut self) -> Option<ast::Comment<'a>> { | ||
152 | self.iter.by_ref().find_map(|el| el.as_token().and_then(ast::Comment::cast)) | ||
153 | } | ||
154 | } | ||
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index ad6d74162..0a35e25d5 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -243,6 +243,8 @@ Grammar( | |||
243 | "PARAM", | 243 | "PARAM", |
244 | "SELF_PARAM", | 244 | "SELF_PARAM", |
245 | "ARG_LIST", | 245 | "ARG_LIST", |
246 | "TYPE_BOUND", | ||
247 | "TYPE_BOUND_LIST", | ||
246 | ], | 248 | ], |
247 | ast: { | 249 | ast: { |
248 | "SourceFile": ( | 250 | "SourceFile": ( |
@@ -293,7 +295,7 @@ Grammar( | |||
293 | "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), | 295 | "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), |
294 | "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), | 296 | "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), |
295 | "TraitDef": ( | 297 | "TraitDef": ( |
296 | traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"], | 298 | traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner", "TypeBoundsOwner"], |
297 | options: ["ItemList"] | 299 | options: ["ItemList"] |
298 | ), | 300 | ), |
299 | "Module": ( | 301 | "Module": ( |
@@ -313,6 +315,7 @@ Grammar( | |||
313 | "DocCommentsOwner", | 315 | "DocCommentsOwner", |
314 | "TypeAscriptionOwner", | 316 | "TypeAscriptionOwner", |
315 | ], | 317 | ], |
318 | options: [ ["body","Expr"]], | ||
316 | ), | 319 | ), |
317 | "StaticDef": ( | 320 | "StaticDef": ( |
318 | traits: [ | 321 | traits: [ |
@@ -323,6 +326,7 @@ Grammar( | |||
323 | "DocCommentsOwner", | 326 | "DocCommentsOwner", |
324 | "TypeAscriptionOwner", | 327 | "TypeAscriptionOwner", |
325 | ], | 328 | ], |
329 | options: [ ["body","Expr"]], | ||
326 | ), | 330 | ), |
327 | "TypeAliasDef": ( | 331 | "TypeAliasDef": ( |
328 | traits: [ | 332 | traits: [ |
@@ -330,7 +334,8 @@ Grammar( | |||
330 | "NameOwner", | 334 | "NameOwner", |
331 | "TypeParamsOwner", | 335 | "TypeParamsOwner", |
332 | "AttrsOwner", | 336 | "AttrsOwner", |
333 | "DocCommentsOwner" | 337 | "DocCommentsOwner", |
338 | "TypeBoundsOwner", | ||
334 | ], | 339 | ], |
335 | options: ["TypeRef"] | 340 | options: ["TypeRef"] |
336 | ), | 341 | ), |
@@ -347,8 +352,12 @@ Grammar( | |||
347 | "PlaceholderType": (), | 352 | "PlaceholderType": (), |
348 | "FnPointerType": (options: ["ParamList", "RetType"]), | 353 | "FnPointerType": (options: ["ParamList", "RetType"]), |
349 | "ForType": (options: ["TypeRef"]), | 354 | "ForType": (options: ["TypeRef"]), |
350 | "ImplTraitType": (), | 355 | "ImplTraitType": ( |
351 | "DynTraitType": (), | 356 | traits: ["TypeBoundsOwner"], |
357 | ), | ||
358 | "DynTraitType": ( | ||
359 | traits: ["TypeBoundsOwner"], | ||
360 | ), | ||
352 | 361 | ||
353 | "TypeRef": ( enum: [ | 362 | "TypeRef": ( enum: [ |
354 | "ParenType", | 363 | "ParenType", |
@@ -456,31 +465,7 @@ Grammar( | |||
456 | "RangeExpr": (), | 465 | "RangeExpr": (), |
457 | "BinExpr": (), | 466 | "BinExpr": (), |
458 | 467 | ||
459 | "IntNumber": ( traits: ["AstToken"] ), | 468 | "Literal": (), |
460 | "FloatNumber": ( traits: ["AstToken"] ), | ||
461 | "String": ( traits: ["AstToken"] ), | ||
462 | "RawString": ( traits: ["AstToken"] ), | ||
463 | "Byte": ( traits: ["AstToken"] ), | ||
464 | "RawByteString": ( traits: ["AstToken"] ), | ||
465 | "ByteString": ( traits: ["AstToken"] ), | ||
466 | "Char": ( traits: ["AstToken"] ), | ||
467 | "TrueKw": ( traits: ["AstToken"] ), | ||
468 | "FalseKw": ( traits: ["AstToken"] ), | ||
469 | "LiteralExpr": ( | ||
470 | enum: [ | ||
471 | "String", | ||
472 | "ByteString", | ||
473 | "RawString", | ||
474 | "RawByteString", | ||
475 | "Char", | ||
476 | "Byte", | ||
477 | "IntNumber", | ||
478 | "FloatNumber", | ||
479 | "TrueKw", | ||
480 | "FalseKw", | ||
481 | ] | ||
482 | ), | ||
483 | "Literal": (options: ["LiteralExpr"]), | ||
484 | 469 | ||
485 | "Expr": ( | 470 | "Expr": ( |
486 | enum: [ | 471 | enum: [ |
@@ -511,6 +496,7 @@ Grammar( | |||
511 | "RangeExpr", | 496 | "RangeExpr", |
512 | "BinExpr", | 497 | "BinExpr", |
513 | "Literal", | 498 | "Literal", |
499 | "MacroCall", | ||
514 | ], | 500 | ], |
515 | ), | 501 | ), |
516 | 502 | ||
@@ -571,13 +557,33 @@ Grammar( | |||
571 | ["lifetime_params", "LifetimeParam" ], | 557 | ["lifetime_params", "LifetimeParam" ], |
572 | ] | 558 | ] |
573 | ), | 559 | ), |
574 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner"] ), | 560 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ), |
575 | "LifetimeParam": ( | 561 | "LifetimeParam": ( |
576 | options: [ "Lifetime"], | ||
577 | traits: ["AttrsOwner"], | 562 | traits: ["AttrsOwner"], |
578 | ), | 563 | ), |
579 | "Lifetime": ( traits: ["AstToken"] ), | 564 | "TypeBound": ( |
580 | "WhereClause": (), | 565 | options: [ |
566 | "TypeRef", | ||
567 | ] | ||
568 | ), | ||
569 | "TypeBoundList": ( | ||
570 | collections: [ | ||
571 | ["bounds", "TypeBound"], | ||
572 | ] | ||
573 | ), | ||
574 | "WherePred": ( | ||
575 | options: [ | ||
576 | "TypeRef", | ||
577 | ], | ||
578 | traits: [ | ||
579 | "TypeBoundsOwner", | ||
580 | ], | ||
581 | ), | ||
582 | "WhereClause": ( | ||
583 | collections: [ | ||
584 | ["predicates", "WherePred"], | ||
585 | ], | ||
586 | ), | ||
581 | "ExprStmt": ( | 587 | "ExprStmt": ( |
582 | options: [ ["expr", "Expr"] ] | 588 | options: [ ["expr", "Expr"] ] |
583 | ), | 589 | ), |
@@ -612,12 +618,10 @@ Grammar( | |||
612 | ] | 618 | ] |
613 | ), | 619 | ), |
614 | "SelfParam": ( | 620 | "SelfParam": ( |
615 | options: ["SelfKw"], | ||
616 | traits: [ | 621 | traits: [ |
617 | "TypeAscriptionOwner", | 622 | "TypeAscriptionOwner", |
618 | ] | 623 | ] |
619 | ), | 624 | ), |
620 | "SelfKw": (), | ||
621 | "Param": ( | 625 | "Param": ( |
622 | options: [ "Pat" ], | 626 | options: [ "Pat" ], |
623 | traits: [ | 627 | traits: [ |
@@ -661,8 +665,6 @@ Grammar( | |||
661 | ]), | 665 | ]), |
662 | "TypeArg": (options: ["TypeRef"]), | 666 | "TypeArg": (options: ["TypeRef"]), |
663 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), | 667 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), |
664 | "LifetimeArg": (options: ["Lifetime"]), | 668 | "LifetimeArg": (), |
665 | "Comment": ( traits: ["AstToken"] ), | ||
666 | "Whitespace": ( traits: ["AstToken"] ), | ||
667 | }, | 669 | }, |
668 | ) | 670 | ) |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 4f3020440..e1088e296 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -38,7 +38,7 @@ pub use crate::{ | |||
38 | ast::AstNode, | 38 | ast::AstNode, |
39 | syntax_error::{SyntaxError, SyntaxErrorKind, Location}, | 39 | syntax_error::{SyntaxError, SyntaxErrorKind, Location}, |
40 | syntax_text::SyntaxText, | 40 | syntax_text::SyntaxText, |
41 | syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder}, | 41 | syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken}, |
42 | ptr::{SyntaxNodePtr, AstPtr}, | 42 | ptr::{SyntaxNodePtr, AstPtr}, |
43 | parsing::{tokenize, Token}, | 43 | parsing::{tokenize, Token}, |
44 | }; | 44 | }; |
@@ -70,7 +70,7 @@ impl SourceFile { | |||
70 | 70 | ||
71 | pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { | 71 | pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { |
72 | parsing::incremental_reparse(self.syntax(), edit, self.errors()) | 72 | parsing::incremental_reparse(self.syntax(), edit, self.errors()) |
73 | .map(|(green_node, errors)| SourceFile::new(green_node, errors)) | 73 | .map(|(green_node, errors, _reparsed_range)| SourceFile::new(green_node, errors)) |
74 | } | 74 | } |
75 | 75 | ||
76 | fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { | 76 | fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { |
@@ -179,15 +179,23 @@ fn api_walkthrough() { | |||
179 | 179 | ||
180 | // There's a bunch of traversal methods on `SyntaxNode`: | 180 | // There's a bunch of traversal methods on `SyntaxNode`: |
181 | assert_eq!(expr_syntax.parent(), Some(block.syntax())); | 181 | assert_eq!(expr_syntax.parent(), Some(block.syntax())); |
182 | assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY)); | 182 | assert_eq!( |
183 | assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE)); | 183 | block.syntax().first_child_or_token().map(|it| it.kind()), |
184 | Some(SyntaxKind::L_CURLY) | ||
185 | ); | ||
186 | assert_eq!( | ||
187 | expr_syntax.next_sibling_or_token().map(|it| it.kind()), | ||
188 | Some(SyntaxKind::WHITESPACE) | ||
189 | ); | ||
184 | 190 | ||
185 | // As well as some iterator helpers: | 191 | // As well as some iterator helpers: |
186 | let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); | 192 | let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); |
187 | assert_eq!(f, Some(&*func)); | 193 | assert_eq!(f, Some(&*func)); |
188 | assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY)); | 194 | assert!(expr_syntax |
195 | .siblings_with_tokens(Direction::Next) | ||
196 | .any(|it| it.kind() == SyntaxKind::R_CURLY)); | ||
189 | assert_eq!( | 197 | assert_eq!( |
190 | expr_syntax.descendants().count(), | 198 | expr_syntax.descendants_with_tokens().count(), |
191 | 8, // 5 tokens `1`, ` `, `+`, ` `, `!` | 199 | 8, // 5 tokens `1`, ` `, `+`, ` `, `!` |
192 | // 2 child literal expressions: `1`, `1` | 200 | // 2 child literal expressions: `1`, `1` |
193 | // 1 the node itself: `1 + 1` | 201 | // 1 the node itself: `1 + 1` |
@@ -196,16 +204,14 @@ fn api_walkthrough() { | |||
196 | // There's also a `preorder` method with a more fine-grained iteration control: | 204 | // There's also a `preorder` method with a more fine-grained iteration control: |
197 | let mut buf = String::new(); | 205 | let mut buf = String::new(); |
198 | let mut indent = 0; | 206 | let mut indent = 0; |
199 | for event in expr_syntax.preorder() { | 207 | for event in expr_syntax.preorder_with_tokens() { |
200 | match event { | 208 | match event { |
201 | WalkEvent::Enter(node) => { | 209 | WalkEvent::Enter(node) => { |
202 | buf += &format!( | 210 | let text = match node { |
203 | "{:indent$}{:?} {:?}\n", | 211 | SyntaxElement::Node(it) => it.text().to_string(), |
204 | " ", | 212 | SyntaxElement::Token(it) => it.text().to_string(), |
205 | node.text(), | 213 | }; |
206 | node.kind(), | 214 | buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent); |
207 | indent = indent | ||
208 | ); | ||
209 | indent += 2; | 215 | indent += 2; |
210 | } | 216 | } |
211 | WalkEvent::Leave(_) => indent -= 2, | 217 | WalkEvent::Leave(_) => indent -= 2, |
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index 7e7f914f5..69887f500 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs | |||
@@ -12,7 +12,7 @@ use ra_parser::Reparser; | |||
12 | use crate::{ | 12 | use crate::{ |
13 | SyntaxKind::*, TextRange, TextUnit, SyntaxError, | 13 | SyntaxKind::*, TextRange, TextUnit, SyntaxError, |
14 | algo, | 14 | algo, |
15 | syntax_node::{GreenNode, SyntaxNode}, | 15 | syntax_node::{GreenNode, SyntaxNode, GreenToken, SyntaxElement}, |
16 | parsing::{ | 16 | parsing::{ |
17 | text_token_source::TextTokenSource, | 17 | text_token_source::TextTokenSource, |
18 | text_tree_sink::TextTreeSink, | 18 | text_tree_sink::TextTreeSink, |
@@ -24,60 +24,62 @@ pub(crate) fn incremental_reparse( | |||
24 | node: &SyntaxNode, | 24 | node: &SyntaxNode, |
25 | edit: &AtomTextEdit, | 25 | edit: &AtomTextEdit, |
26 | errors: Vec<SyntaxError>, | 26 | errors: Vec<SyntaxError>, |
27 | ) -> Option<(GreenNode, Vec<SyntaxError>)> { | 27 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
28 | let (node, green, new_errors) = | 28 | if let Some((green, old_range)) = reparse_token(node, &edit) { |
29 | reparse_leaf(node, &edit).or_else(|| reparse_block(node, &edit))?; | 29 | return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range)); |
30 | let green_root = node.replace_with(green); | 30 | } |
31 | let errors = merge_errors(errors, new_errors, node, edit); | 31 | |
32 | Some((green_root, errors)) | 32 | if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) { |
33 | return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); | ||
34 | } | ||
35 | None | ||
33 | } | 36 | } |
34 | 37 | ||
35 | fn reparse_leaf<'node>( | 38 | fn reparse_token<'node>( |
36 | root: &'node SyntaxNode, | 39 | root: &'node SyntaxNode, |
37 | edit: &AtomTextEdit, | 40 | edit: &AtomTextEdit, |
38 | ) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { | 41 | ) -> Option<(GreenNode, TextRange)> { |
39 | let node = algo::find_covering_node(root, edit.delete); | 42 | let token = algo::find_covering_element(root, edit.delete).as_token()?; |
40 | match node.kind() { | 43 | match token.kind() { |
41 | WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { | 44 | WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { |
42 | if node.kind() == WHITESPACE || node.kind() == COMMENT { | 45 | if token.kind() == WHITESPACE || token.kind() == COMMENT { |
43 | // removing a new line may extends previous token | 46 | // removing a new line may extends previous token |
44 | if node.text().to_string()[edit.delete - node.range().start()].contains('\n') { | 47 | if token.text().to_string()[edit.delete - token.range().start()].contains('\n') { |
45 | return None; | 48 | return None; |
46 | } | 49 | } |
47 | } | 50 | } |
48 | 51 | ||
49 | let text = get_text_after_edit(node, &edit); | 52 | let text = get_text_after_edit(token.into(), &edit); |
50 | let tokens = tokenize(&text); | 53 | let lex_tokens = tokenize(&text); |
51 | let token = match tokens[..] { | 54 | let lex_token = match lex_tokens[..] { |
52 | [token] if token.kind == node.kind() => token, | 55 | [lex_token] if lex_token.kind == token.kind() => lex_token, |
53 | _ => return None, | 56 | _ => return None, |
54 | }; | 57 | }; |
55 | 58 | ||
56 | if token.kind == IDENT && is_contextual_kw(&text) { | 59 | if lex_token.kind == IDENT && is_contextual_kw(&text) { |
57 | return None; | 60 | return None; |
58 | } | 61 | } |
59 | 62 | ||
60 | if let Some(next_char) = root.text().char_at(node.range().end()) { | 63 | if let Some(next_char) = root.text().char_at(token.range().end()) { |
61 | let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); | 64 | let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); |
62 | if tokens_with_next_char.len() == 1 { | 65 | if tokens_with_next_char.len() == 1 { |
63 | return None; | 66 | return None; |
64 | } | 67 | } |
65 | } | 68 | } |
66 | 69 | ||
67 | let green = GreenNode::new_leaf(node.kind(), text.into()); | 70 | let new_token = GreenToken::new(token.kind(), text.into()); |
68 | let new_errors = vec![]; | 71 | Some((token.replace_with(new_token), token.range())) |
69 | Some((node, green, new_errors)) | ||
70 | } | 72 | } |
71 | _ => None, | 73 | _ => None, |
72 | } | 74 | } |
73 | } | 75 | } |
74 | 76 | ||
75 | fn reparse_block<'node>( | 77 | fn reparse_block<'node>( |
76 | node: &'node SyntaxNode, | 78 | root: &'node SyntaxNode, |
77 | edit: &AtomTextEdit, | 79 | edit: &AtomTextEdit, |
78 | ) -> Option<(&'node SyntaxNode, GreenNode, Vec<SyntaxError>)> { | 80 | ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { |
79 | let (node, reparser) = find_reparsable_node(node, edit.delete)?; | 81 | let (node, reparser) = find_reparsable_node(root, edit.delete)?; |
80 | let text = get_text_after_edit(node, &edit); | 82 | let text = get_text_after_edit(node.into(), &edit); |
81 | let tokens = tokenize(&text); | 83 | let tokens = tokenize(&text); |
82 | if !is_balanced(&tokens) { | 84 | if !is_balanced(&tokens) { |
83 | return None; | 85 | return None; |
@@ -86,12 +88,16 @@ fn reparse_block<'node>( | |||
86 | let mut tree_sink = TextTreeSink::new(&text, &tokens); | 88 | let mut tree_sink = TextTreeSink::new(&text, &tokens); |
87 | reparser.parse(&token_source, &mut tree_sink); | 89 | reparser.parse(&token_source, &mut tree_sink); |
88 | let (green, new_errors) = tree_sink.finish(); | 90 | let (green, new_errors) = tree_sink.finish(); |
89 | Some((node, green, new_errors)) | 91 | Some((node.replace_with(green), new_errors, node.range())) |
90 | } | 92 | } |
91 | 93 | ||
92 | fn get_text_after_edit(node: &SyntaxNode, edit: &AtomTextEdit) -> String { | 94 | fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { |
93 | let edit = AtomTextEdit::replace(edit.delete - node.range().start(), edit.insert.clone()); | 95 | let edit = AtomTextEdit::replace(edit.delete - element.range().start(), edit.insert.clone()); |
94 | edit.apply(node.text().to_string()) | 96 | let text = match element { |
97 | SyntaxElement::Token(token) => token.text().to_string(), | ||
98 | SyntaxElement::Node(node) => node.text().to_string(), | ||
99 | }; | ||
100 | edit.apply(text) | ||
95 | } | 101 | } |
96 | 102 | ||
97 | fn is_contextual_kw(text: &str) -> bool { | 103 | fn is_contextual_kw(text: &str) -> bool { |
@@ -102,9 +108,13 @@ fn is_contextual_kw(text: &str) -> bool { | |||
102 | } | 108 | } |
103 | 109 | ||
104 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { | 110 | fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { |
105 | let node = algo::find_covering_node(node, range); | 111 | let node = algo::find_covering_element(node, range); |
106 | node.ancestors().find_map(|node| { | 112 | let mut ancestors = match node { |
107 | let first_child = node.first_child().map(|it| it.kind()); | 113 | SyntaxElement::Token(it) => it.parent().ancestors(), |
114 | SyntaxElement::Node(it) => it.ancestors(), | ||
115 | }; | ||
116 | ancestors.find_map(|node| { | ||
117 | let first_child = node.first_child_or_token().map(|it| it.kind()); | ||
108 | let parent = node.parent().map(|it| it.kind()); | 118 | let parent = node.parent().map(|it| it.kind()); |
109 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) | 119 | Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) |
110 | }) | 120 | }) |
@@ -136,19 +146,19 @@ fn is_balanced(tokens: &[Token]) -> bool { | |||
136 | fn merge_errors( | 146 | fn merge_errors( |
137 | old_errors: Vec<SyntaxError>, | 147 | old_errors: Vec<SyntaxError>, |
138 | new_errors: Vec<SyntaxError>, | 148 | new_errors: Vec<SyntaxError>, |
139 | old_node: &SyntaxNode, | 149 | old_range: TextRange, |
140 | edit: &AtomTextEdit, | 150 | edit: &AtomTextEdit, |
141 | ) -> Vec<SyntaxError> { | 151 | ) -> Vec<SyntaxError> { |
142 | let mut res = Vec::new(); | 152 | let mut res = Vec::new(); |
143 | for e in old_errors { | 153 | for e in old_errors { |
144 | if e.offset() <= old_node.range().start() { | 154 | if e.offset() <= old_range.start() { |
145 | res.push(e) | 155 | res.push(e) |
146 | } else if e.offset() >= old_node.range().end() { | 156 | } else if e.offset() >= old_range.end() { |
147 | res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); | 157 | res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); |
148 | } | 158 | } |
149 | } | 159 | } |
150 | for e in new_errors { | 160 | for e in new_errors { |
151 | res.push(e.add_offset(old_node.range().start(), 0.into())); | 161 | res.push(e.add_offset(old_range.start(), 0.into())); |
152 | } | 162 | } |
153 | res | 163 | res |
154 | } | 164 | } |
@@ -160,13 +170,7 @@ mod tests { | |||
160 | use crate::{SourceFile, AstNode}; | 170 | use crate::{SourceFile, AstNode}; |
161 | use super::*; | 171 | use super::*; |
162 | 172 | ||
163 | fn do_check<F>(before: &str, replace_with: &str, reparser: F) | 173 | fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { |
164 | where | ||
165 | for<'a> F: Fn( | ||
166 | &'a SyntaxNode, | ||
167 | &AtomTextEdit, | ||
168 | ) -> Option<(&'a SyntaxNode, GreenNode, Vec<SyntaxError>)>, | ||
169 | { | ||
170 | let (range, before) = extract_range(before); | 174 | let (range, before) = extract_range(before); |
171 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); | 175 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); |
172 | let after = edit.apply(before.clone()); | 176 | let after = edit.apply(before.clone()); |
@@ -175,23 +179,20 @@ mod tests { | |||
175 | let incrementally_reparsed = { | 179 | let incrementally_reparsed = { |
176 | let f = SourceFile::parse(&before); | 180 | let f = SourceFile::parse(&before); |
177 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; | 181 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; |
178 | let (node, green, new_errors) = | 182 | let (green, new_errors, range) = |
179 | reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); | 183 | incremental_reparse(f.syntax(), &edit, f.errors()).unwrap(); |
180 | let green_root = node.replace_with(green); | 184 | assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); |
181 | let errors = super::merge_errors(f.errors(), new_errors, node, &edit); | 185 | SourceFile::new(green, new_errors) |
182 | SourceFile::new(green_root, errors) | ||
183 | }; | 186 | }; |
184 | 187 | ||
185 | assert_eq_text!( | 188 | assert_eq_text!( |
186 | &fully_reparsed.syntax().debug_dump(), | 189 | &fully_reparsed.syntax().debug_dump(), |
187 | &incrementally_reparsed.syntax().debug_dump(), | 190 | &incrementally_reparsed.syntax().debug_dump(), |
188 | ) | 191 | ); |
189 | } | 192 | } |
190 | 193 | ||
191 | #[test] | 194 | #[test] // FIXME: some test here actually test token reparsing |
192 | fn reparse_block_tests() { | 195 | fn reparse_block_tests() { |
193 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_block); | ||
194 | |||
195 | do_check( | 196 | do_check( |
196 | r" | 197 | r" |
197 | fn foo() { | 198 | fn foo() { |
@@ -199,6 +200,7 @@ fn foo() { | |||
199 | } | 200 | } |
200 | ", | 201 | ", |
201 | "baz", | 202 | "baz", |
203 | 3, | ||
202 | ); | 204 | ); |
203 | do_check( | 205 | do_check( |
204 | r" | 206 | r" |
@@ -207,6 +209,7 @@ fn foo() { | |||
207 | } | 209 | } |
208 | ", | 210 | ", |
209 | "baz", | 211 | "baz", |
212 | 25, | ||
210 | ); | 213 | ); |
211 | do_check( | 214 | do_check( |
212 | r" | 215 | r" |
@@ -215,6 +218,7 @@ struct Foo { | |||
215 | } | 218 | } |
216 | ", | 219 | ", |
217 | ",\n g: (),", | 220 | ",\n g: (),", |
221 | 14, | ||
218 | ); | 222 | ); |
219 | do_check( | 223 | do_check( |
220 | r" | 224 | r" |
@@ -225,6 +229,7 @@ fn foo { | |||
225 | } | 229 | } |
226 | ", | 230 | ", |
227 | "62", | 231 | "62", |
232 | 31, // FIXME: reparse only int literal here | ||
228 | ); | 233 | ); |
229 | do_check( | 234 | do_check( |
230 | r" | 235 | r" |
@@ -233,7 +238,9 @@ mod foo { | |||
233 | } | 238 | } |
234 | ", | 239 | ", |
235 | "bar", | 240 | "bar", |
241 | 11, | ||
236 | ); | 242 | ); |
243 | |||
237 | do_check( | 244 | do_check( |
238 | r" | 245 | r" |
239 | trait Foo { | 246 | trait Foo { |
@@ -241,6 +248,7 @@ trait Foo { | |||
241 | } | 248 | } |
242 | ", | 249 | ", |
243 | "Output", | 250 | "Output", |
251 | 3, | ||
244 | ); | 252 | ); |
245 | do_check( | 253 | do_check( |
246 | r" | 254 | r" |
@@ -249,13 +257,9 @@ impl IntoIterator<Item=i32> for Foo { | |||
249 | } | 257 | } |
250 | ", | 258 | ", |
251 | "n next(", | 259 | "n next(", |
260 | 9, | ||
252 | ); | 261 | ); |
253 | do_check( | 262 | do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10); |
254 | r" | ||
255 | use a::b::{foo,<|>,bar<|>}; | ||
256 | ", | ||
257 | "baz", | ||
258 | ); | ||
259 | do_check( | 263 | do_check( |
260 | r" | 264 | r" |
261 | pub enum A { | 265 | pub enum A { |
@@ -263,12 +267,14 @@ pub enum A { | |||
263 | } | 267 | } |
264 | ", | 268 | ", |
265 | "\nBar;\n", | 269 | "\nBar;\n", |
270 | 11, | ||
266 | ); | 271 | ); |
267 | do_check( | 272 | do_check( |
268 | r" | 273 | r" |
269 | foo!{a, b<|><|> d} | 274 | foo!{a, b<|><|> d} |
270 | ", | 275 | ", |
271 | ", c[3]", | 276 | ", c[3]", |
277 | 8, | ||
272 | ); | 278 | ); |
273 | do_check( | 279 | do_check( |
274 | r" | 280 | r" |
@@ -277,6 +283,7 @@ fn foo() { | |||
277 | } | 283 | } |
278 | ", | 284 | ", |
279 | "123", | 285 | "123", |
286 | 14, | ||
280 | ); | 287 | ); |
281 | do_check( | 288 | do_check( |
282 | r" | 289 | r" |
@@ -285,54 +292,60 @@ extern { | |||
285 | } | 292 | } |
286 | ", | 293 | ", |
287 | " exit(code: c_int)", | 294 | " exit(code: c_int)", |
295 | 11, | ||
288 | ); | 296 | ); |
289 | } | 297 | } |
290 | 298 | ||
291 | #[test] | 299 | #[test] |
292 | fn reparse_leaf_tests() { | 300 | fn reparse_token_tests() { |
293 | let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf); | ||
294 | |||
295 | do_check( | 301 | do_check( |
296 | r"<|><|> | 302 | r"<|><|> |
297 | fn foo() -> i32 { 1 } | 303 | fn foo() -> i32 { 1 } |
298 | ", | 304 | ", |
299 | "\n\n\n \n", | 305 | "\n\n\n \n", |
306 | 1, | ||
300 | ); | 307 | ); |
301 | do_check( | 308 | do_check( |
302 | r" | 309 | r" |
303 | fn foo() -> <|><|> {} | 310 | fn foo() -> <|><|> {} |
304 | ", | 311 | ", |
305 | " \n", | 312 | " \n", |
313 | 2, | ||
306 | ); | 314 | ); |
307 | do_check( | 315 | do_check( |
308 | r" | 316 | r" |
309 | fn <|>foo<|>() -> i32 { 1 } | 317 | fn <|>foo<|>() -> i32 { 1 } |
310 | ", | 318 | ", |
311 | "bar", | 319 | "bar", |
320 | 3, | ||
312 | ); | 321 | ); |
313 | do_check( | 322 | do_check( |
314 | r" | 323 | r" |
315 | fn foo<|><|>foo() { } | 324 | fn foo<|><|>foo() { } |
316 | ", | 325 | ", |
317 | "bar", | 326 | "bar", |
327 | 6, | ||
318 | ); | 328 | ); |
319 | do_check( | 329 | do_check( |
320 | r" | 330 | r" |
321 | fn foo /* <|><|> */ () {} | 331 | fn foo /* <|><|> */ () {} |
322 | ", | 332 | ", |
323 | "some comment", | 333 | "some comment", |
334 | 6, | ||
324 | ); | 335 | ); |
325 | do_check( | 336 | do_check( |
326 | r" | 337 | r" |
327 | fn baz <|><|> () {} | 338 | fn baz <|><|> () {} |
328 | ", | 339 | ", |
329 | " \t\t\n\n", | 340 | " \t\t\n\n", |
341 | 2, | ||
330 | ); | 342 | ); |
331 | do_check( | 343 | do_check( |
332 | r" | 344 | r" |
333 | fn baz <|><|> () {} | 345 | fn baz <|><|> () {} |
334 | ", | 346 | ", |
335 | " \t\t\n\n", | 347 | " \t\t\n\n", |
348 | 2, | ||
336 | ); | 349 | ); |
337 | do_check( | 350 | do_check( |
338 | r" | 351 | r" |
@@ -340,24 +353,28 @@ fn baz <|><|> () {} | |||
340 | mod { } | 353 | mod { } |
341 | ", | 354 | ", |
342 | "c", | 355 | "c", |
356 | 14, | ||
343 | ); | 357 | ); |
344 | do_check( | 358 | do_check( |
345 | r#" | 359 | r#" |
346 | fn -> &str { "Hello<|><|>" } | 360 | fn -> &str { "Hello<|><|>" } |
347 | "#, | 361 | "#, |
348 | ", world", | 362 | ", world", |
363 | 7, | ||
349 | ); | 364 | ); |
350 | do_check( | 365 | do_check( |
351 | r#" | 366 | r#" |
352 | fn -> &str { // "Hello<|><|>" | 367 | fn -> &str { // "Hello<|><|>" |
353 | "#, | 368 | "#, |
354 | ", world", | 369 | ", world", |
370 | 10, | ||
355 | ); | 371 | ); |
356 | do_check( | 372 | do_check( |
357 | r##" | 373 | r##" |
358 | fn -> &str { r#"Hello<|><|>"# | 374 | fn -> &str { r#"Hello<|><|>"# |
359 | "##, | 375 | "##, |
360 | ", world", | 376 | ", world", |
377 | 10, | ||
361 | ); | 378 | ); |
362 | do_check( | 379 | do_check( |
363 | r" | 380 | r" |
@@ -367,6 +384,7 @@ enum Foo { | |||
367 | } | 384 | } |
368 | ", | 385 | ", |
369 | "Clone", | 386 | "Clone", |
387 | 4, | ||
370 | ); | 388 | ); |
371 | } | 389 | } |
372 | } | 390 | } |
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs index b17d06c61..71fc515f2 100644 --- a/crates/ra_syntax/src/parsing/text_tree_sink.rs +++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs | |||
@@ -28,10 +28,10 @@ enum State { | |||
28 | } | 28 | } |
29 | 29 | ||
30 | impl<'a> TreeSink for TextTreeSink<'a> { | 30 | impl<'a> TreeSink for TextTreeSink<'a> { |
31 | fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { | 31 | fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { |
32 | match mem::replace(&mut self.state, State::Normal) { | 32 | match mem::replace(&mut self.state, State::Normal) { |
33 | State::PendingStart => unreachable!(), | 33 | State::PendingStart => unreachable!(), |
34 | State::PendingFinish => self.inner.finish_branch(), | 34 | State::PendingFinish => self.inner.finish_node(), |
35 | State::Normal => (), | 35 | State::Normal => (), |
36 | } | 36 | } |
37 | self.eat_trivias(); | 37 | self.eat_trivias(); |
@@ -40,18 +40,18 @@ impl<'a> TreeSink for TextTreeSink<'a> { | |||
40 | .iter() | 40 | .iter() |
41 | .map(|it| it.len) | 41 | .map(|it| it.len) |
42 | .sum::<TextUnit>(); | 42 | .sum::<TextUnit>(); |
43 | self.do_leaf(kind, len, n_tokens); | 43 | self.do_token(kind, len, n_tokens); |
44 | } | 44 | } |
45 | 45 | ||
46 | fn start_branch(&mut self, kind: SyntaxKind) { | 46 | fn start_node(&mut self, kind: SyntaxKind) { |
47 | match mem::replace(&mut self.state, State::Normal) { | 47 | match mem::replace(&mut self.state, State::Normal) { |
48 | State::PendingStart => { | 48 | State::PendingStart => { |
49 | self.inner.start_branch(kind); | 49 | self.inner.start_node(kind); |
50 | // No need to attach trivias to previous node: there is no | 50 | // No need to attach trivias to previous node: there is no |
51 | // previous node. | 51 | // previous node. |
52 | return; | 52 | return; |
53 | } | 53 | } |
54 | State::PendingFinish => self.inner.finish_branch(), | 54 | State::PendingFinish => self.inner.finish_node(), |
55 | State::Normal => (), | 55 | State::Normal => (), |
56 | } | 56 | } |
57 | 57 | ||
@@ -71,14 +71,14 @@ impl<'a> TreeSink for TextTreeSink<'a> { | |||
71 | n_attached_trivias(kind, leading_trivias) | 71 | n_attached_trivias(kind, leading_trivias) |
72 | }; | 72 | }; |
73 | self.eat_n_trivias(n_trivias - n_attached_trivias); | 73 | self.eat_n_trivias(n_trivias - n_attached_trivias); |
74 | self.inner.start_branch(kind); | 74 | self.inner.start_node(kind); |
75 | self.eat_n_trivias(n_attached_trivias); | 75 | self.eat_n_trivias(n_attached_trivias); |
76 | } | 76 | } |
77 | 77 | ||
78 | fn finish_branch(&mut self) { | 78 | fn finish_node(&mut self) { |
79 | match mem::replace(&mut self.state, State::PendingFinish) { | 79 | match mem::replace(&mut self.state, State::PendingFinish) { |
80 | State::PendingStart => unreachable!(), | 80 | State::PendingStart => unreachable!(), |
81 | State::PendingFinish => self.inner.finish_branch(), | 81 | State::PendingFinish => self.inner.finish_node(), |
82 | State::Normal => (), | 82 | State::Normal => (), |
83 | } | 83 | } |
84 | } | 84 | } |
@@ -104,7 +104,7 @@ impl<'a> TextTreeSink<'a> { | |||
104 | match mem::replace(&mut self.state, State::Normal) { | 104 | match mem::replace(&mut self.state, State::Normal) { |
105 | State::PendingFinish => { | 105 | State::PendingFinish => { |
106 | self.eat_trivias(); | 106 | self.eat_trivias(); |
107 | self.inner.finish_branch() | 107 | self.inner.finish_node() |
108 | } | 108 | } |
109 | State::PendingStart | State::Normal => unreachable!(), | 109 | State::PendingStart | State::Normal => unreachable!(), |
110 | } | 110 | } |
@@ -117,7 +117,7 @@ impl<'a> TextTreeSink<'a> { | |||
117 | if !token.kind.is_trivia() { | 117 | if !token.kind.is_trivia() { |
118 | break; | 118 | break; |
119 | } | 119 | } |
120 | self.do_leaf(token.kind, token.len, 1); | 120 | self.do_token(token.kind, token.len, 1); |
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
@@ -125,16 +125,16 @@ impl<'a> TextTreeSink<'a> { | |||
125 | for _ in 0..n { | 125 | for _ in 0..n { |
126 | let token = self.tokens[self.token_pos]; | 126 | let token = self.tokens[self.token_pos]; |
127 | assert!(token.kind.is_trivia()); | 127 | assert!(token.kind.is_trivia()); |
128 | self.do_leaf(token.kind, token.len, 1); | 128 | self.do_token(token.kind, token.len, 1); |
129 | } | 129 | } |
130 | } | 130 | } |
131 | 131 | ||
132 | fn do_leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { | 132 | fn do_token(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { |
133 | let range = TextRange::offset_len(self.text_pos, len); | 133 | let range = TextRange::offset_len(self.text_pos, len); |
134 | let text: SmolStr = self.text[range].into(); | 134 | let text: SmolStr = self.text[range].into(); |
135 | self.text_pos += len; | 135 | self.text_pos += len; |
136 | self.token_pos += n_tokens; | 136 | self.token_pos += n_tokens; |
137 | self.inner.leaf(kind, text); | 137 | self.inner.token(kind, text); |
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
diff --git a/crates/ra_syntax/src/string_lexing.rs b/crates/ra_syntax/src/string_lexing.rs index 349733f3f..4c3eea3d2 100644 --- a/crates/ra_syntax/src/string_lexing.rs +++ b/crates/ra_syntax/src/string_lexing.rs | |||
@@ -1,7 +1,333 @@ | |||
1 | mod parser; | 1 | use crate::{TextRange, TextUnit}; |
2 | mod string; | 2 | use self::StringComponentKind::*; |
3 | 3 | ||
4 | pub use self::{ | 4 | #[derive(Debug, Eq, PartialEq, Clone)] |
5 | parser::{StringComponent, StringComponentKind}, | 5 | pub(crate) struct StringComponent { |
6 | string::{parse_string_literal, parse_char_literal, parse_byte_literal, parse_byte_string_literal}, | 6 | pub(crate) range: TextRange, |
7 | }; | 7 | pub(crate) kind: StringComponentKind, |
8 | } | ||
9 | |||
10 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
11 | pub(crate) enum StringComponentKind { | ||
12 | IgnoreNewline, | ||
13 | CodePoint, | ||
14 | AsciiEscape, | ||
15 | AsciiCodeEscape, | ||
16 | UnicodeEscape, | ||
17 | } | ||
18 | |||
19 | pub(crate) fn parse_quoted_literal( | ||
20 | prefix: Option<char>, | ||
21 | quote: char, | ||
22 | src: &str, | ||
23 | ) -> StringComponentIter { | ||
24 | let prefix = prefix.map(|p| match p { | ||
25 | 'b' => b'b', | ||
26 | _ => panic!("invalid prefix"), | ||
27 | }); | ||
28 | let quote = match quote { | ||
29 | '\'' => b'\'', | ||
30 | '"' => b'"', | ||
31 | _ => panic!("invalid quote"), | ||
32 | }; | ||
33 | StringComponentIter { src, prefix, quote, pos: 0, has_closing_quote: false, suffix: None } | ||
34 | } | ||
35 | |||
36 | pub(crate) struct StringComponentIter<'a> { | ||
37 | src: &'a str, | ||
38 | prefix: Option<u8>, | ||
39 | quote: u8, | ||
40 | pos: usize, | ||
41 | pub(crate) has_closing_quote: bool, | ||
42 | pub(crate) suffix: Option<TextRange>, | ||
43 | } | ||
44 | |||
45 | impl<'a> Iterator for StringComponentIter<'a> { | ||
46 | type Item = StringComponent; | ||
47 | fn next(&mut self) -> Option<StringComponent> { | ||
48 | if self.pos == 0 { | ||
49 | if let Some(prefix) = self.prefix { | ||
50 | assert!( | ||
51 | self.advance() == prefix as char, | ||
52 | "literal should start with a {:?}", | ||
53 | prefix as char, | ||
54 | ); | ||
55 | } | ||
56 | assert!( | ||
57 | self.advance() == self.quote as char, | ||
58 | "literal should start with a {:?}", | ||
59 | self.quote as char, | ||
60 | ); | ||
61 | } | ||
62 | |||
63 | if let Some(component) = self.parse_component() { | ||
64 | return Some(component); | ||
65 | } | ||
66 | |||
67 | // We get here when there are no char components left to parse | ||
68 | if self.peek() == Some(self.quote as char) { | ||
69 | self.advance(); | ||
70 | self.has_closing_quote = true; | ||
71 | if let Some(range) = self.parse_suffix() { | ||
72 | self.suffix = Some(range); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | assert!( | ||
77 | self.peek() == None, | ||
78 | "literal should leave no unparsed input: src = {:?}, pos = {}, length = {}", | ||
79 | self.src, | ||
80 | self.pos, | ||
81 | self.src.len() | ||
82 | ); | ||
83 | |||
84 | None | ||
85 | } | ||
86 | } | ||
87 | |||
88 | impl<'a> StringComponentIter<'a> { | ||
89 | fn peek(&self) -> Option<char> { | ||
90 | if self.pos == self.src.len() { | ||
91 | return None; | ||
92 | } | ||
93 | |||
94 | self.src[self.pos..].chars().next() | ||
95 | } | ||
96 | |||
97 | fn advance(&mut self) -> char { | ||
98 | let next = self.peek().expect("cannot advance if end of input is reached"); | ||
99 | self.pos += next.len_utf8(); | ||
100 | next | ||
101 | } | ||
102 | |||
103 | fn parse_component(&mut self) -> Option<StringComponent> { | ||
104 | let next = self.peek()?; | ||
105 | |||
106 | // Ignore string close | ||
107 | if next == self.quote as char { | ||
108 | return None; | ||
109 | } | ||
110 | |||
111 | let start = self.start_range(); | ||
112 | self.advance(); | ||
113 | |||
114 | if next == '\\' { | ||
115 | // Strings can use `\` to ignore newlines, so we first try to parse one of those | ||
116 | // before falling back to parsing char escapes | ||
117 | if self.quote == b'"' { | ||
118 | if let Some(component) = self.parse_ignore_newline(start) { | ||
119 | return Some(component); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | Some(self.parse_escape(start)) | ||
124 | } else { | ||
125 | Some(self.finish_component(start, CodePoint)) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | fn parse_ignore_newline(&mut self, start: TextUnit) -> Option<StringComponent> { | ||
130 | // In string literals, when a `\` occurs immediately before the newline, the `\`, | ||
131 | // the newline, and all whitespace at the beginning of the next line are ignored | ||
132 | match self.peek() { | ||
133 | Some('\n') | Some('\r') => { | ||
134 | self.skip_whitespace(); | ||
135 | Some(self.finish_component(start, IgnoreNewline)) | ||
136 | } | ||
137 | _ => None, | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fn skip_whitespace(&mut self) { | ||
142 | while self.peek().map(|c| c.is_whitespace()) == Some(true) { | ||
143 | self.advance(); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | fn parse_escape(&mut self, start: TextUnit) -> StringComponent { | ||
148 | if self.peek().is_none() { | ||
149 | return self.finish_component(start, AsciiEscape); | ||
150 | } | ||
151 | |||
152 | let next = self.advance(); | ||
153 | match next { | ||
154 | 'x' => self.parse_ascii_code_escape(start), | ||
155 | 'u' => self.parse_unicode_escape(start), | ||
156 | _ => self.finish_component(start, AsciiEscape), | ||
157 | } | ||
158 | } | ||
159 | |||
160 | fn parse_unicode_escape(&mut self, start: TextUnit) -> StringComponent { | ||
161 | match self.peek() { | ||
162 | Some('{') => { | ||
163 | self.advance(); | ||
164 | |||
165 | // Parse anything until we reach `}` | ||
166 | while let Some(next) = self.peek() { | ||
167 | self.advance(); | ||
168 | if next == '}' { | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | self.finish_component(start, UnicodeEscape) | ||
174 | } | ||
175 | Some(_) | None => self.finish_component(start, UnicodeEscape), | ||
176 | } | ||
177 | } | ||
178 | |||
179 | fn parse_ascii_code_escape(&mut self, start: TextUnit) -> StringComponent { | ||
180 | let code_start = self.pos; | ||
181 | while let Some(next) = self.peek() { | ||
182 | if next == '\'' || (self.pos - code_start == 2) { | ||
183 | break; | ||
184 | } | ||
185 | |||
186 | self.advance(); | ||
187 | } | ||
188 | self.finish_component(start, AsciiCodeEscape) | ||
189 | } | ||
190 | |||
191 | fn parse_suffix(&mut self) -> Option<TextRange> { | ||
192 | let start = self.start_range(); | ||
193 | let _ = self.peek()?; | ||
194 | while let Some(_) = self.peek() { | ||
195 | self.advance(); | ||
196 | } | ||
197 | Some(self.finish_range(start)) | ||
198 | } | ||
199 | |||
200 | fn start_range(&self) -> TextUnit { | ||
201 | TextUnit::from_usize(self.pos) | ||
202 | } | ||
203 | |||
204 | fn finish_range(&self, start: TextUnit) -> TextRange { | ||
205 | TextRange::from_to(start, TextUnit::from_usize(self.pos)) | ||
206 | } | ||
207 | |||
208 | fn finish_component(&self, start: TextUnit, kind: StringComponentKind) -> StringComponent { | ||
209 | let range = self.finish_range(start); | ||
210 | StringComponent { range, kind } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | #[cfg(test)] | ||
215 | mod tests { | ||
216 | use super::*; | ||
217 | |||
218 | fn parse(src: &str) -> (bool, Vec<StringComponent>) { | ||
219 | let component_iterator = &mut parse_quoted_literal(None, '\'', src); | ||
220 | let components: Vec<_> = component_iterator.collect(); | ||
221 | (component_iterator.has_closing_quote, components) | ||
222 | } | ||
223 | |||
224 | fn unclosed_char_component(src: &str) -> StringComponent { | ||
225 | let (has_closing_quote, components) = parse(src); | ||
226 | assert!(!has_closing_quote, "char should not have closing quote"); | ||
227 | assert!(components.len() == 1); | ||
228 | components[0].clone() | ||
229 | } | ||
230 | |||
231 | fn closed_char_component(src: &str) -> StringComponent { | ||
232 | let (has_closing_quote, components) = parse(src); | ||
233 | assert!(has_closing_quote, "char should have closing quote"); | ||
234 | assert!(components.len() == 1, "Literal: {}\nComponents: {:#?}", src, components); | ||
235 | components[0].clone() | ||
236 | } | ||
237 | |||
238 | fn closed_char_components(src: &str) -> Vec<StringComponent> { | ||
239 | let (has_closing_quote, components) = parse(src); | ||
240 | assert!(has_closing_quote, "char should have closing quote"); | ||
241 | components | ||
242 | } | ||
243 | |||
244 | fn range_closed(src: &str) -> TextRange { | ||
245 | TextRange::from_to(1.into(), (src.len() as u32 - 1).into()) | ||
246 | } | ||
247 | |||
248 | fn range_unclosed(src: &str) -> TextRange { | ||
249 | TextRange::from_to(1.into(), (src.len() as u32).into()) | ||
250 | } | ||
251 | |||
252 | #[test] | ||
253 | fn test_unicode_escapes() { | ||
254 | let unicode_escapes = &[r"{DEAD}", "{BEEF}", "{FF}", "{}", ""]; | ||
255 | for escape in unicode_escapes { | ||
256 | let escape_sequence = format!(r"'\u{}'", escape); | ||
257 | let component = closed_char_component(&escape_sequence); | ||
258 | let expected_range = range_closed(&escape_sequence); | ||
259 | assert_eq!(component.kind, UnicodeEscape); | ||
260 | assert_eq!(component.range, expected_range); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | #[test] | ||
265 | fn test_unicode_escapes_unclosed() { | ||
266 | let unicode_escapes = &["{DEAD", "{BEEF", "{FF"]; | ||
267 | for escape in unicode_escapes { | ||
268 | let escape_sequence = format!(r"'\u{}'", escape); | ||
269 | let component = unclosed_char_component(&escape_sequence); | ||
270 | let expected_range = range_unclosed(&escape_sequence); | ||
271 | assert_eq!(component.kind, UnicodeEscape); | ||
272 | assert_eq!(component.range, expected_range); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | #[test] | ||
277 | fn test_empty_char() { | ||
278 | let (has_closing_quote, components) = parse("''"); | ||
279 | assert!(has_closing_quote, "char should have closing quote"); | ||
280 | assert!(components.len() == 0); | ||
281 | } | ||
282 | |||
283 | #[test] | ||
284 | fn test_unclosed_char() { | ||
285 | let component = unclosed_char_component("'a"); | ||
286 | assert!(component.kind == CodePoint); | ||
287 | assert!(component.range == TextRange::from_to(1.into(), 2.into())); | ||
288 | } | ||
289 | |||
290 | #[test] | ||
291 | fn test_digit_escapes() { | ||
292 | let literals = &[r"", r"5", r"55"]; | ||
293 | |||
294 | for literal in literals { | ||
295 | let lit_text = format!(r"'\x{}'", literal); | ||
296 | let component = closed_char_component(&lit_text); | ||
297 | assert!(component.kind == AsciiCodeEscape); | ||
298 | assert!(component.range == range_closed(&lit_text)); | ||
299 | } | ||
300 | |||
301 | // More than 2 digits starts a new codepoint | ||
302 | let components = closed_char_components(r"'\x555'"); | ||
303 | assert!(components.len() == 2); | ||
304 | assert!(components[1].kind == CodePoint); | ||
305 | } | ||
306 | |||
307 | #[test] | ||
308 | fn test_ascii_escapes() { | ||
309 | let literals = &[ | ||
310 | r"\'", "\\\"", // equivalent to \" | ||
311 | r"\n", r"\r", r"\t", r"\\", r"\0", | ||
312 | ]; | ||
313 | |||
314 | for literal in literals { | ||
315 | let lit_text = format!("'{}'", literal); | ||
316 | let component = closed_char_component(&lit_text); | ||
317 | assert!(component.kind == AsciiEscape); | ||
318 | assert!(component.range == range_closed(&lit_text)); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn test_no_escapes() { | ||
324 | let literals = &['"', 'n', 'r', 't', '0', 'x', 'u']; | ||
325 | |||
326 | for &literal in literals { | ||
327 | let lit_text = format!("'{}'", literal); | ||
328 | let component = closed_char_component(&lit_text); | ||
329 | assert!(component.kind == CodePoint); | ||
330 | assert!(component.range == range_closed(&lit_text)); | ||
331 | } | ||
332 | } | ||
333 | } | ||
diff --git a/crates/ra_syntax/src/string_lexing/parser.rs b/crates/ra_syntax/src/string_lexing/parser.rs deleted file mode 100644 index 7469eb903..000000000 --- a/crates/ra_syntax/src/string_lexing/parser.rs +++ /dev/null | |||
@@ -1,168 +0,0 @@ | |||
1 | use rowan::{TextRange, TextUnit}; | ||
2 | |||
3 | use self::StringComponentKind::*; | ||
4 | |||
5 | pub struct Parser<'a> { | ||
6 | pub(super) quote: u8, | ||
7 | pub(super) src: &'a str, | ||
8 | pub(super) pos: usize, | ||
9 | } | ||
10 | |||
11 | impl<'a> Parser<'a> { | ||
12 | pub fn new(src: &'a str, quote: u8) -> Parser<'a> { | ||
13 | Parser { quote, src, pos: 0 } | ||
14 | } | ||
15 | |||
16 | // Utility methods | ||
17 | |||
18 | pub fn peek(&self) -> Option<char> { | ||
19 | if self.pos == self.src.len() { | ||
20 | return None; | ||
21 | } | ||
22 | |||
23 | self.src[self.pos..].chars().next() | ||
24 | } | ||
25 | |||
26 | pub fn advance(&mut self) -> char { | ||
27 | let next = self.peek().expect("cannot advance if end of input is reached"); | ||
28 | self.pos += next.len_utf8(); | ||
29 | next | ||
30 | } | ||
31 | |||
32 | pub fn skip_whitespace(&mut self) { | ||
33 | while self.peek().map(|c| c.is_whitespace()) == Some(true) { | ||
34 | self.advance(); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | pub fn get_pos(&self) -> TextUnit { | ||
39 | (self.pos as u32).into() | ||
40 | } | ||
41 | |||
42 | // Char parsing methods | ||
43 | |||
44 | fn parse_unicode_escape(&mut self, start: TextUnit) -> StringComponent { | ||
45 | match self.peek() { | ||
46 | Some('{') => { | ||
47 | self.advance(); | ||
48 | |||
49 | // Parse anything until we reach `}` | ||
50 | while let Some(next) = self.peek() { | ||
51 | self.advance(); | ||
52 | if next == '}' { | ||
53 | break; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | let end = self.get_pos(); | ||
58 | StringComponent::new(TextRange::from_to(start, end), UnicodeEscape) | ||
59 | } | ||
60 | Some(_) | None => { | ||
61 | let end = self.get_pos(); | ||
62 | StringComponent::new(TextRange::from_to(start, end), UnicodeEscape) | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | fn parse_ascii_code_escape(&mut self, start: TextUnit) -> StringComponent { | ||
68 | let code_start = self.get_pos(); | ||
69 | while let Some(next) = self.peek() { | ||
70 | if next == '\'' || (self.get_pos() - code_start == 2.into()) { | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | self.advance(); | ||
75 | } | ||
76 | |||
77 | let end = self.get_pos(); | ||
78 | StringComponent::new(TextRange::from_to(start, end), AsciiCodeEscape) | ||
79 | } | ||
80 | |||
81 | fn parse_escape(&mut self, start: TextUnit) -> StringComponent { | ||
82 | if self.peek().is_none() { | ||
83 | return StringComponent::new(TextRange::from_to(start, self.get_pos()), AsciiEscape); | ||
84 | } | ||
85 | |||
86 | let next = self.advance(); | ||
87 | let end = self.get_pos(); | ||
88 | let range = TextRange::from_to(start, end); | ||
89 | match next { | ||
90 | 'x' => self.parse_ascii_code_escape(start), | ||
91 | 'u' => self.parse_unicode_escape(start), | ||
92 | _ => StringComponent::new(range, AsciiEscape), | ||
93 | } | ||
94 | } | ||
95 | |||
96 | pub fn parse_ignore_newline(&mut self, start: TextUnit) -> Option<StringComponent> { | ||
97 | // In string literals, when a `\` occurs immediately before the newline, the `\`, | ||
98 | // the newline, and all whitespace at the beginning of the next line are ignored | ||
99 | match self.peek() { | ||
100 | Some('\n') | Some('\r') => { | ||
101 | self.skip_whitespace(); | ||
102 | Some(StringComponent::new( | ||
103 | TextRange::from_to(start, self.get_pos()), | ||
104 | StringComponentKind::IgnoreNewline, | ||
105 | )) | ||
106 | } | ||
107 | _ => None, | ||
108 | } | ||
109 | } | ||
110 | |||
111 | pub fn parse_component(&mut self) -> Option<StringComponent> { | ||
112 | let next = self.peek()?; | ||
113 | |||
114 | // Ignore string close | ||
115 | if next == self.quote as char { | ||
116 | return None; | ||
117 | } | ||
118 | |||
119 | let start = self.get_pos(); | ||
120 | self.advance(); | ||
121 | |||
122 | if next == '\\' { | ||
123 | // Strings can use `\` to ignore newlines, so we first try to parse one of those | ||
124 | // before falling back to parsing char escapes | ||
125 | if self.quote == b'"' { | ||
126 | if let Some(component) = self.parse_ignore_newline(start) { | ||
127 | return Some(component); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | Some(self.parse_escape(start)) | ||
132 | } else { | ||
133 | let end = self.get_pos(); | ||
134 | Some(StringComponent::new(TextRange::from_to(start, end), CodePoint)) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | pub fn parse_suffix(&mut self) -> Option<TextRange> { | ||
139 | let start = self.get_pos(); | ||
140 | let _ = self.peek()?; | ||
141 | while let Some(_) = self.peek() { | ||
142 | self.advance(); | ||
143 | } | ||
144 | let end = self.get_pos(); | ||
145 | Some(TextRange::from_to(start, end)) | ||
146 | } | ||
147 | } | ||
148 | |||
149 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
150 | pub struct StringComponent { | ||
151 | pub range: TextRange, | ||
152 | pub kind: StringComponentKind, | ||
153 | } | ||
154 | |||
155 | impl StringComponent { | ||
156 | fn new(range: TextRange, kind: StringComponentKind) -> StringComponent { | ||
157 | StringComponent { range, kind } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | #[derive(Debug, Eq, PartialEq, Clone)] | ||
162 | pub enum StringComponentKind { | ||
163 | IgnoreNewline, | ||
164 | CodePoint, | ||
165 | AsciiEscape, | ||
166 | AsciiCodeEscape, | ||
167 | UnicodeEscape, | ||
168 | } | ||
diff --git a/crates/ra_syntax/src/string_lexing/string.rs b/crates/ra_syntax/src/string_lexing/string.rs deleted file mode 100644 index a4742a0d1..000000000 --- a/crates/ra_syntax/src/string_lexing/string.rs +++ /dev/null | |||
@@ -1,222 +0,0 @@ | |||
1 | use crate::{ | ||
2 | TextRange, | ||
3 | string_lexing::{ | ||
4 | parser::Parser, | ||
5 | StringComponent, | ||
6 | }}; | ||
7 | |||
8 | pub fn parse_string_literal(src: &str) -> StringComponentIterator { | ||
9 | StringComponentIterator { | ||
10 | parser: Parser::new(src, b'"'), | ||
11 | has_closing_quote: false, | ||
12 | suffix: None, | ||
13 | prefix: None, | ||
14 | quote: b'"', | ||
15 | } | ||
16 | } | ||
17 | |||
18 | pub fn parse_byte_string_literal(src: &str) -> StringComponentIterator { | ||
19 | StringComponentIterator { | ||
20 | parser: Parser::new(src, b'"'), | ||
21 | has_closing_quote: false, | ||
22 | suffix: None, | ||
23 | prefix: Some(b'b'), | ||
24 | quote: b'"', | ||
25 | } | ||
26 | } | ||
27 | |||
28 | pub fn parse_char_literal(src: &str) -> StringComponentIterator { | ||
29 | StringComponentIterator { | ||
30 | parser: Parser::new(src, b'\''), | ||
31 | has_closing_quote: false, | ||
32 | suffix: None, | ||
33 | prefix: None, | ||
34 | quote: b'\'', | ||
35 | } | ||
36 | } | ||
37 | |||
38 | pub fn parse_byte_literal(src: &str) -> StringComponentIterator { | ||
39 | StringComponentIterator { | ||
40 | parser: Parser::new(src, b'\''), | ||
41 | has_closing_quote: false, | ||
42 | suffix: None, | ||
43 | prefix: Some(b'b'), | ||
44 | quote: b'\'', | ||
45 | } | ||
46 | } | ||
47 | |||
48 | pub struct StringComponentIterator<'a> { | ||
49 | parser: Parser<'a>, | ||
50 | pub has_closing_quote: bool, | ||
51 | pub suffix: Option<TextRange>, | ||
52 | prefix: Option<u8>, | ||
53 | quote: u8, | ||
54 | } | ||
55 | |||
56 | impl<'a> Iterator for StringComponentIterator<'a> { | ||
57 | type Item = StringComponent; | ||
58 | fn next(&mut self) -> Option<StringComponent> { | ||
59 | if self.parser.pos == 0 { | ||
60 | if let Some(prefix) = self.prefix { | ||
61 | assert!( | ||
62 | self.parser.advance() == prefix as char, | ||
63 | "literal should start with a {:?}", | ||
64 | prefix as char, | ||
65 | ); | ||
66 | } | ||
67 | assert!( | ||
68 | self.parser.advance() == self.quote as char, | ||
69 | "literal should start with a {:?}", | ||
70 | self.quote as char, | ||
71 | ); | ||
72 | } | ||
73 | |||
74 | if let Some(component) = self.parser.parse_component() { | ||
75 | return Some(component); | ||
76 | } | ||
77 | |||
78 | // We get here when there are no char components left to parse | ||
79 | if self.parser.peek() == Some(self.quote as char) { | ||
80 | self.parser.advance(); | ||
81 | self.has_closing_quote = true; | ||
82 | if let Some(range) = self.parser.parse_suffix() { | ||
83 | self.suffix = Some(range); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | assert!( | ||
88 | self.parser.peek() == None, | ||
89 | "literal should leave no unparsed input: src = {:?}, pos = {}, length = {}", | ||
90 | self.parser.src, | ||
91 | self.parser.pos, | ||
92 | self.parser.src.len() | ||
93 | ); | ||
94 | |||
95 | None | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #[cfg(test)] | ||
100 | mod tests { | ||
101 | use rowan::TextRange; | ||
102 | use crate::string_lexing::{ | ||
103 | StringComponent, | ||
104 | StringComponentKind::*, | ||
105 | }; | ||
106 | |||
107 | fn parse(src: &str) -> (bool, Vec<StringComponent>) { | ||
108 | let component_iterator = &mut super::parse_char_literal(src); | ||
109 | let components: Vec<_> = component_iterator.collect(); | ||
110 | (component_iterator.has_closing_quote, components) | ||
111 | } | ||
112 | |||
113 | fn unclosed_char_component(src: &str) -> StringComponent { | ||
114 | let (has_closing_quote, components) = parse(src); | ||
115 | assert!(!has_closing_quote, "char should not have closing quote"); | ||
116 | assert!(components.len() == 1); | ||
117 | components[0].clone() | ||
118 | } | ||
119 | |||
120 | fn closed_char_component(src: &str) -> StringComponent { | ||
121 | let (has_closing_quote, components) = parse(src); | ||
122 | assert!(has_closing_quote, "char should have closing quote"); | ||
123 | assert!(components.len() == 1, "Literal: {}\nComponents: {:#?}", src, components); | ||
124 | components[0].clone() | ||
125 | } | ||
126 | |||
127 | fn closed_char_components(src: &str) -> Vec<StringComponent> { | ||
128 | let (has_closing_quote, components) = parse(src); | ||
129 | assert!(has_closing_quote, "char should have closing quote"); | ||
130 | components | ||
131 | } | ||
132 | |||
133 | fn range_closed(src: &str) -> TextRange { | ||
134 | TextRange::from_to(1.into(), (src.len() as u32 - 1).into()) | ||
135 | } | ||
136 | |||
137 | fn range_unclosed(src: &str) -> TextRange { | ||
138 | TextRange::from_to(1.into(), (src.len() as u32).into()) | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn test_unicode_escapes() { | ||
143 | let unicode_escapes = &[r"{DEAD}", "{BEEF}", "{FF}", "{}", ""]; | ||
144 | for escape in unicode_escapes { | ||
145 | let escape_sequence = format!(r"'\u{}'", escape); | ||
146 | let component = closed_char_component(&escape_sequence); | ||
147 | let expected_range = range_closed(&escape_sequence); | ||
148 | assert_eq!(component.kind, UnicodeEscape); | ||
149 | assert_eq!(component.range, expected_range); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | #[test] | ||
154 | fn test_unicode_escapes_unclosed() { | ||
155 | let unicode_escapes = &["{DEAD", "{BEEF", "{FF"]; | ||
156 | for escape in unicode_escapes { | ||
157 | let escape_sequence = format!(r"'\u{}'", escape); | ||
158 | let component = unclosed_char_component(&escape_sequence); | ||
159 | let expected_range = range_unclosed(&escape_sequence); | ||
160 | assert_eq!(component.kind, UnicodeEscape); | ||
161 | assert_eq!(component.range, expected_range); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn test_empty_char() { | ||
167 | let (has_closing_quote, components) = parse("''"); | ||
168 | assert!(has_closing_quote, "char should have closing quote"); | ||
169 | assert!(components.len() == 0); | ||
170 | } | ||
171 | |||
172 | #[test] | ||
173 | fn test_unclosed_char() { | ||
174 | let component = unclosed_char_component("'a"); | ||
175 | assert!(component.kind == CodePoint); | ||
176 | assert!(component.range == TextRange::from_to(1.into(), 2.into())); | ||
177 | } | ||
178 | |||
179 | #[test] | ||
180 | fn test_digit_escapes() { | ||
181 | let literals = &[r"", r"5", r"55"]; | ||
182 | |||
183 | for literal in literals { | ||
184 | let lit_text = format!(r"'\x{}'", literal); | ||
185 | let component = closed_char_component(&lit_text); | ||
186 | assert!(component.kind == AsciiCodeEscape); | ||
187 | assert!(component.range == range_closed(&lit_text)); | ||
188 | } | ||
189 | |||
190 | // More than 2 digits starts a new codepoint | ||
191 | let components = closed_char_components(r"'\x555'"); | ||
192 | assert!(components.len() == 2); | ||
193 | assert!(components[1].kind == CodePoint); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn test_ascii_escapes() { | ||
198 | let literals = &[ | ||
199 | r"\'", "\\\"", // equivalent to \" | ||
200 | r"\n", r"\r", r"\t", r"\\", r"\0", | ||
201 | ]; | ||
202 | |||
203 | for literal in literals { | ||
204 | let lit_text = format!("'{}'", literal); | ||
205 | let component = closed_char_component(&lit_text); | ||
206 | assert!(component.kind == AsciiEscape); | ||
207 | assert!(component.range == range_closed(&lit_text)); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | #[test] | ||
212 | fn test_no_escapes() { | ||
213 | let literals = &['"', 'n', 'r', 't', '0', 'x', 'u']; | ||
214 | |||
215 | for &literal in literals { | ||
216 | let lit_text = format!("'{}'", literal); | ||
217 | let component = closed_char_component(&lit_text); | ||
218 | assert!(component.kind == CodePoint); | ||
219 | assert!(component.range == range_closed(&lit_text)); | ||
220 | } | ||
221 | } | ||
222 | } | ||
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index e5b4cdb11..a88a348ad 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs | |||
@@ -29,6 +29,9 @@ impl Types for RaTypes { | |||
29 | } | 29 | } |
30 | 30 | ||
31 | pub(crate) type GreenNode = rowan::GreenNode<RaTypes>; | 31 | pub(crate) type GreenNode = rowan::GreenNode<RaTypes>; |
32 | pub(crate) type GreenToken = rowan::GreenToken<RaTypes>; | ||
33 | #[allow(unused)] | ||
34 | pub(crate) type GreenElement = rowan::GreenElement<RaTypes>; | ||
32 | 35 | ||
33 | /// Marker trait for CST and AST nodes | 36 | /// Marker trait for CST and AST nodes |
34 | pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {} | 37 | pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode<RaTypes>> {} |
@@ -113,11 +116,13 @@ impl ToOwned for SyntaxNode { | |||
113 | 116 | ||
114 | impl fmt::Debug for SyntaxNode { | 117 | impl fmt::Debug for SyntaxNode { |
115 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | 118 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
116 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | 119 | write!(fmt, "{:?}@{:?}", self.kind(), self.range()) |
117 | if has_short_text(self.kind()) { | 120 | } |
118 | write!(fmt, " \"{}\"", self.text())?; | 121 | } |
119 | } | 122 | |
120 | Ok(()) | 123 | impl fmt::Display for SyntaxNode { |
124 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
125 | fmt::Display::fmt(&self.text(), fmt) | ||
121 | } | 126 | } |
122 | } | 127 | } |
123 | 128 | ||
@@ -145,14 +150,6 @@ impl SyntaxNode { | |||
145 | SyntaxText::new(self) | 150 | SyntaxText::new(self) |
146 | } | 151 | } |
147 | 152 | ||
148 | pub fn is_leaf(&self) -> bool { | ||
149 | self.0.is_leaf() | ||
150 | } | ||
151 | |||
152 | pub fn leaf_text(&self) -> Option<&SmolStr> { | ||
153 | self.0.leaf_text() | ||
154 | } | ||
155 | |||
156 | pub fn parent(&self) -> Option<&SyntaxNode> { | 153 | pub fn parent(&self) -> Option<&SyntaxNode> { |
157 | self.0.parent().map(SyntaxNode::from_repr) | 154 | self.0.parent().map(SyntaxNode::from_repr) |
158 | } | 155 | } |
@@ -161,22 +158,50 @@ impl SyntaxNode { | |||
161 | self.0.first_child().map(SyntaxNode::from_repr) | 158 | self.0.first_child().map(SyntaxNode::from_repr) |
162 | } | 159 | } |
163 | 160 | ||
161 | pub fn first_child_or_token(&self) -> Option<SyntaxElement> { | ||
162 | self.0.first_child_or_token().map(SyntaxElement::from) | ||
163 | } | ||
164 | |||
164 | pub fn last_child(&self) -> Option<&SyntaxNode> { | 165 | pub fn last_child(&self) -> Option<&SyntaxNode> { |
165 | self.0.last_child().map(SyntaxNode::from_repr) | 166 | self.0.last_child().map(SyntaxNode::from_repr) |
166 | } | 167 | } |
167 | 168 | ||
169 | pub fn last_child_or_token(&self) -> Option<SyntaxElement> { | ||
170 | self.0.last_child_or_token().map(SyntaxElement::from) | ||
171 | } | ||
172 | |||
168 | pub fn next_sibling(&self) -> Option<&SyntaxNode> { | 173 | pub fn next_sibling(&self) -> Option<&SyntaxNode> { |
169 | self.0.next_sibling().map(SyntaxNode::from_repr) | 174 | self.0.next_sibling().map(SyntaxNode::from_repr) |
170 | } | 175 | } |
171 | 176 | ||
177 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> { | ||
178 | self.0.next_sibling_or_token().map(SyntaxElement::from) | ||
179 | } | ||
180 | |||
172 | pub fn prev_sibling(&self) -> Option<&SyntaxNode> { | 181 | pub fn prev_sibling(&self) -> Option<&SyntaxNode> { |
173 | self.0.prev_sibling().map(SyntaxNode::from_repr) | 182 | self.0.prev_sibling().map(SyntaxNode::from_repr) |
174 | } | 183 | } |
175 | 184 | ||
185 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> { | ||
186 | self.0.prev_sibling_or_token().map(SyntaxElement::from) | ||
187 | } | ||
188 | |||
176 | pub fn children(&self) -> SyntaxNodeChildren { | 189 | pub fn children(&self) -> SyntaxNodeChildren { |
177 | SyntaxNodeChildren(self.0.children()) | 190 | SyntaxNodeChildren(self.0.children()) |
178 | } | 191 | } |
179 | 192 | ||
193 | pub fn children_with_tokens(&self) -> SyntaxElementChildren { | ||
194 | SyntaxElementChildren(self.0.children_with_tokens()) | ||
195 | } | ||
196 | |||
197 | pub fn first_token(&self) -> Option<SyntaxToken> { | ||
198 | self.0.first_token().map(SyntaxToken::from) | ||
199 | } | ||
200 | |||
201 | pub fn last_token(&self) -> Option<SyntaxToken> { | ||
202 | self.0.last_token().map(SyntaxToken::from) | ||
203 | } | ||
204 | |||
180 | pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> { | 205 | pub fn ancestors(&self) -> impl Iterator<Item = &SyntaxNode> { |
181 | crate::algo::generate(Some(self), |&node| node.parent()) | 206 | crate::algo::generate(Some(self), |&node| node.parent()) |
182 | } | 207 | } |
@@ -188,6 +213,13 @@ impl SyntaxNode { | |||
188 | }) | 213 | }) |
189 | } | 214 | } |
190 | 215 | ||
216 | pub fn descendants_with_tokens(&self) -> impl Iterator<Item = SyntaxElement> { | ||
217 | self.preorder_with_tokens().filter_map(|event| match event { | ||
218 | WalkEvent::Enter(it) => Some(it), | ||
219 | WalkEvent::Leave(_) => None, | ||
220 | }) | ||
221 | } | ||
222 | |||
191 | pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> { | 223 | pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = &SyntaxNode> { |
192 | crate::algo::generate(Some(self), move |&node| match direction { | 224 | crate::algo::generate(Some(self), move |&node| match direction { |
193 | Direction::Next => node.next_sibling(), | 225 | Direction::Next => node.next_sibling(), |
@@ -195,6 +227,17 @@ impl SyntaxNode { | |||
195 | }) | 227 | }) |
196 | } | 228 | } |
197 | 229 | ||
230 | pub fn siblings_with_tokens( | ||
231 | &self, | ||
232 | direction: Direction, | ||
233 | ) -> impl Iterator<Item = SyntaxElement> { | ||
234 | let me: SyntaxElement = self.into(); | ||
235 | crate::algo::generate(Some(me), move |el| match direction { | ||
236 | Direction::Next => el.next_sibling_or_token(), | ||
237 | Direction::Prev => el.prev_sibling_or_token(), | ||
238 | }) | ||
239 | } | ||
240 | |||
198 | pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> { | 241 | pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<&SyntaxNode>> { |
199 | self.0.preorder().map(|event| match event { | 242 | self.0.preorder().map(|event| match event { |
200 | WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), | 243 | WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), |
@@ -202,6 +245,13 @@ impl SyntaxNode { | |||
202 | }) | 245 | }) |
203 | } | 246 | } |
204 | 247 | ||
248 | pub fn preorder_with_tokens(&self) -> impl Iterator<Item = WalkEvent<SyntaxElement>> { | ||
249 | self.0.preorder_with_tokens().map(|event| match event { | ||
250 | WalkEvent::Enter(n) => WalkEvent::Enter(n.into()), | ||
251 | WalkEvent::Leave(n) => WalkEvent::Leave(n.into()), | ||
252 | }) | ||
253 | } | ||
254 | |||
205 | pub fn memory_size_of_subtree(&self) -> usize { | 255 | pub fn memory_size_of_subtree(&self) -> usize { |
206 | self.0.memory_size_of_subtree() | 256 | self.0.memory_size_of_subtree() |
207 | } | 257 | } |
@@ -223,17 +273,20 @@ impl SyntaxNode { | |||
223 | }; | 273 | }; |
224 | } | 274 | } |
225 | 275 | ||
226 | for event in self.preorder() { | 276 | for event in self.preorder_with_tokens() { |
227 | match event { | 277 | match event { |
228 | WalkEvent::Enter(node) => { | 278 | WalkEvent::Enter(element) => { |
229 | indent!(); | 279 | indent!(); |
230 | writeln!(buf, "{:?}", node).unwrap(); | 280 | match element { |
231 | if node.first_child().is_none() { | 281 | SyntaxElement::Node(node) => writeln!(buf, "{:?}", node).unwrap(), |
232 | let off = node.range().end(); | 282 | SyntaxElement::Token(token) => { |
233 | while err_pos < errors.len() && errors[err_pos].offset() <= off { | 283 | writeln!(buf, "{:?}", token).unwrap(); |
234 | indent!(); | 284 | let off = token.range().end(); |
235 | writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); | 285 | while err_pos < errors.len() && errors[err_pos].offset() <= off { |
236 | err_pos += 1; | 286 | indent!(); |
287 | writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); | ||
288 | err_pos += 1; | ||
289 | } | ||
237 | } | 290 | } |
238 | } | 291 | } |
239 | level += 1; | 292 | level += 1; |
@@ -255,7 +308,179 @@ impl SyntaxNode { | |||
255 | } | 308 | } |
256 | 309 | ||
257 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { | 310 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { |
258 | self.0.replace_self(replacement) | 311 | self.0.replace_with(replacement) |
312 | } | ||
313 | } | ||
314 | |||
315 | #[derive(Clone, Copy, PartialEq, Eq, Hash)] | ||
316 | pub struct SyntaxToken<'a>(pub(crate) rowan::SyntaxToken<'a, RaTypes>); | ||
317 | |||
318 | //FIXME: always output text | ||
319 | impl<'a> fmt::Debug for SyntaxToken<'a> { | ||
320 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
321 | write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; | ||
322 | if self.text().len() < 25 { | ||
323 | return write!(fmt, " {:?}", self.text()); | ||
324 | } | ||
325 | let text = self.text().as_str(); | ||
326 | for idx in 21..25 { | ||
327 | if text.is_char_boundary(idx) { | ||
328 | let text = format!("{} ...", &text[..idx]); | ||
329 | return write!(fmt, " {:?}", text); | ||
330 | } | ||
331 | } | ||
332 | unreachable!() | ||
333 | } | ||
334 | } | ||
335 | |||
336 | impl<'a> fmt::Display for SyntaxToken<'a> { | ||
337 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
338 | fmt::Display::fmt(self.text(), fmt) | ||
339 | } | ||
340 | } | ||
341 | |||
342 | impl<'a> From<rowan::SyntaxToken<'a, RaTypes>> for SyntaxToken<'a> { | ||
343 | fn from(t: rowan::SyntaxToken<'a, RaTypes>) -> Self { | ||
344 | SyntaxToken(t) | ||
345 | } | ||
346 | } | ||
347 | |||
348 | impl<'a> SyntaxToken<'a> { | ||
349 | pub fn kind(&self) -> SyntaxKind { | ||
350 | self.0.kind() | ||
351 | } | ||
352 | |||
353 | pub fn text(&self) -> &'a SmolStr { | ||
354 | self.0.text() | ||
355 | } | ||
356 | |||
357 | pub fn range(&self) -> TextRange { | ||
358 | self.0.range() | ||
359 | } | ||
360 | |||
361 | pub fn parent(&self) -> &'a SyntaxNode { | ||
362 | SyntaxNode::from_repr(self.0.parent()) | ||
363 | } | ||
364 | |||
365 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
366 | self.0.next_sibling_or_token().map(SyntaxElement::from) | ||
367 | } | ||
368 | |||
369 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
370 | self.0.prev_sibling_or_token().map(SyntaxElement::from) | ||
371 | } | ||
372 | |||
373 | pub fn siblings_with_tokens( | ||
374 | &self, | ||
375 | direction: Direction, | ||
376 | ) -> impl Iterator<Item = SyntaxElement<'a>> { | ||
377 | let me: SyntaxElement = (*self).into(); | ||
378 | crate::algo::generate(Some(me), move |el| match direction { | ||
379 | Direction::Next => el.next_sibling_or_token(), | ||
380 | Direction::Prev => el.prev_sibling_or_token(), | ||
381 | }) | ||
382 | } | ||
383 | |||
384 | pub fn next_token(&self) -> Option<SyntaxToken<'a>> { | ||
385 | self.0.next_token().map(SyntaxToken::from) | ||
386 | } | ||
387 | |||
388 | pub fn prev_token(&self) -> Option<SyntaxToken<'a>> { | ||
389 | self.0.prev_token().map(SyntaxToken::from) | ||
390 | } | ||
391 | |||
392 | pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode { | ||
393 | self.0.replace_with(new_token) | ||
394 | } | ||
395 | } | ||
396 | |||
397 | #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] | ||
398 | pub enum SyntaxElement<'a> { | ||
399 | Node(&'a SyntaxNode), | ||
400 | Token(SyntaxToken<'a>), | ||
401 | } | ||
402 | |||
403 | impl<'a> fmt::Display for SyntaxElement<'a> { | ||
404 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
405 | match self { | ||
406 | SyntaxElement::Node(it) => fmt::Display::fmt(it, fmt), | ||
407 | SyntaxElement::Token(it) => fmt::Display::fmt(it, fmt), | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | |||
412 | impl<'a> SyntaxElement<'a> { | ||
413 | pub fn kind(&self) -> SyntaxKind { | ||
414 | match self { | ||
415 | SyntaxElement::Node(it) => it.kind(), | ||
416 | SyntaxElement::Token(it) => it.kind(), | ||
417 | } | ||
418 | } | ||
419 | |||
420 | pub fn as_node(&self) -> Option<&'a SyntaxNode> { | ||
421 | match self { | ||
422 | SyntaxElement::Node(node) => Some(*node), | ||
423 | SyntaxElement::Token(_) => None, | ||
424 | } | ||
425 | } | ||
426 | |||
427 | pub fn as_token(&self) -> Option<SyntaxToken<'a>> { | ||
428 | match self { | ||
429 | SyntaxElement::Node(_) => None, | ||
430 | SyntaxElement::Token(token) => Some(*token), | ||
431 | } | ||
432 | } | ||
433 | |||
434 | pub fn next_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
435 | match self { | ||
436 | SyntaxElement::Node(it) => it.next_sibling_or_token(), | ||
437 | SyntaxElement::Token(it) => it.next_sibling_or_token(), | ||
438 | } | ||
439 | } | ||
440 | |||
441 | pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement<'a>> { | ||
442 | match self { | ||
443 | SyntaxElement::Node(it) => it.prev_sibling_or_token(), | ||
444 | SyntaxElement::Token(it) => it.prev_sibling_or_token(), | ||
445 | } | ||
446 | } | ||
447 | |||
448 | pub fn ancestors(&self) -> impl Iterator<Item = &'a SyntaxNode> { | ||
449 | match self { | ||
450 | SyntaxElement::Node(it) => it, | ||
451 | SyntaxElement::Token(it) => it.parent(), | ||
452 | } | ||
453 | .ancestors() | ||
454 | } | ||
455 | } | ||
456 | |||
457 | impl<'a> From<rowan::SyntaxElement<'a, RaTypes>> for SyntaxElement<'a> { | ||
458 | fn from(el: rowan::SyntaxElement<'a, RaTypes>) -> Self { | ||
459 | match el { | ||
460 | rowan::SyntaxElement::Node(n) => SyntaxElement::Node(SyntaxNode::from_repr(n)), | ||
461 | rowan::SyntaxElement::Token(t) => SyntaxElement::Token(t.into()), | ||
462 | } | ||
463 | } | ||
464 | } | ||
465 | |||
466 | impl<'a> From<&'a SyntaxNode> for SyntaxElement<'a> { | ||
467 | fn from(node: &'a SyntaxNode) -> SyntaxElement<'a> { | ||
468 | SyntaxElement::Node(node) | ||
469 | } | ||
470 | } | ||
471 | |||
472 | impl<'a> From<SyntaxToken<'a>> for SyntaxElement<'a> { | ||
473 | fn from(token: SyntaxToken<'a>) -> SyntaxElement<'a> { | ||
474 | SyntaxElement::Token(token) | ||
475 | } | ||
476 | } | ||
477 | |||
478 | impl<'a> SyntaxElement<'a> { | ||
479 | pub fn range(&self) -> TextRange { | ||
480 | match self { | ||
481 | SyntaxElement::Node(it) => it.range(), | ||
482 | SyntaxElement::Token(it) => it.range(), | ||
483 | } | ||
259 | } | 484 | } |
260 | } | 485 | } |
261 | 486 | ||
@@ -270,11 +495,14 @@ impl<'a> Iterator for SyntaxNodeChildren<'a> { | |||
270 | } | 495 | } |
271 | } | 496 | } |
272 | 497 | ||
273 | fn has_short_text(kind: SyntaxKind) -> bool { | 498 | #[derive(Debug)] |
274 | use crate::SyntaxKind::*; | 499 | pub struct SyntaxElementChildren<'a>(rowan::SyntaxElementChildren<'a, RaTypes>); |
275 | match kind { | 500 | |
276 | IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true, | 501 | impl<'a> Iterator for SyntaxElementChildren<'a> { |
277 | _ => false, | 502 | type Item = SyntaxElement<'a>; |
503 | |||
504 | fn next(&mut self) -> Option<SyntaxElement<'a>> { | ||
505 | self.0.next().map(SyntaxElement::from) | ||
278 | } | 506 | } |
279 | } | 507 | } |
280 | 508 | ||
@@ -304,16 +532,16 @@ impl SyntaxTreeBuilder { | |||
304 | node | 532 | node |
305 | } | 533 | } |
306 | 534 | ||
307 | pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) { | 535 | pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { |
308 | self.inner.leaf(kind, text) | 536 | self.inner.token(kind, text) |
309 | } | 537 | } |
310 | 538 | ||
311 | pub fn start_branch(&mut self, kind: SyntaxKind) { | 539 | pub fn start_node(&mut self, kind: SyntaxKind) { |
312 | self.inner.start_internal(kind) | 540 | self.inner.start_node(kind) |
313 | } | 541 | } |
314 | 542 | ||
315 | pub fn finish_branch(&mut self) { | 543 | pub fn finish_node(&mut self) { |
316 | self.inner.finish_internal() | 544 | self.inner.finish_node() |
317 | } | 545 | } |
318 | 546 | ||
319 | pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { | 547 | pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { |
diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs index 84e5b231a..6bb2ff461 100644 --- a/crates/ra_syntax/src/syntax_text.rs +++ b/crates/ra_syntax/src/syntax_text.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::{fmt, ops}; | 1 | use std::{fmt, ops}; |
2 | 2 | ||
3 | use crate::{SyntaxNode, TextRange, TextUnit}; | 3 | use crate::{SyntaxNode, TextRange, TextUnit, SyntaxElement}; |
4 | 4 | ||
5 | #[derive(Clone)] | 5 | #[derive(Clone)] |
6 | pub struct SyntaxText<'a> { | 6 | pub struct SyntaxText<'a> { |
@@ -15,11 +15,14 @@ impl<'a> SyntaxText<'a> { | |||
15 | 15 | ||
16 | pub fn chunks(&self) -> impl Iterator<Item = &'a str> { | 16 | pub fn chunks(&self) -> impl Iterator<Item = &'a str> { |
17 | let range = self.range; | 17 | let range = self.range; |
18 | self.node.descendants().filter_map(move |node| { | 18 | self.node.descendants_with_tokens().filter_map(move |el| match el { |
19 | let text = node.leaf_text()?; | 19 | SyntaxElement::Token(t) => { |
20 | let range = range.intersection(&node.range())?; | 20 | let text = t.text(); |
21 | let range = range - node.range().start(); | 21 | let range = range.intersection(&t.range())?; |
22 | Some(&text[range]) | 22 | let range = range - t.range().start(); |
23 | Some(&text[range]) | ||
24 | } | ||
25 | SyntaxElement::Node(_) => None, | ||
23 | }) | 26 | }) |
24 | } | 27 | } |
25 | 28 | ||
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 69f344d65..fc534df83 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -6,7 +6,7 @@ mod block; | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | SourceFile, SyntaxError, AstNode, SyntaxNode, | 8 | SourceFile, SyntaxError, AstNode, SyntaxNode, |
9 | SyntaxKind::{L_CURLY, R_CURLY}, | 9 | SyntaxKind::{L_CURLY, R_CURLY, BYTE, BYTE_STRING, STRING, CHAR}, |
10 | ast, | 10 | ast, |
11 | algo::visit::{visitor_ctx, VisitorCtx}, | 11 | algo::visit::{visitor_ctx, VisitorCtx}, |
12 | }; | 12 | }; |
@@ -15,16 +15,24 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> { | |||
15 | let mut errors = Vec::new(); | 15 | let mut errors = Vec::new(); |
16 | for node in file.syntax().descendants() { | 16 | for node in file.syntax().descendants() { |
17 | let _ = visitor_ctx(&mut errors) | 17 | let _ = visitor_ctx(&mut errors) |
18 | .visit::<ast::Byte, _>(byte::validate_byte_node) | 18 | .visit::<ast::Literal, _>(validate_literal) |
19 | .visit::<ast::ByteString, _>(byte_string::validate_byte_string_node) | ||
20 | .visit::<ast::Char, _>(char::validate_char_node) | ||
21 | .visit::<ast::String, _>(string::validate_string_node) | ||
22 | .visit::<ast::Block, _>(block::validate_block_node) | 19 | .visit::<ast::Block, _>(block::validate_block_node) |
23 | .accept(node); | 20 | .accept(node); |
24 | } | 21 | } |
25 | errors | 22 | errors |
26 | } | 23 | } |
27 | 24 | ||
25 | // FIXME: kill duplication | ||
26 | fn validate_literal(literal: &ast::Literal, acc: &mut Vec<SyntaxError>) { | ||
27 | match literal.token().kind() { | ||
28 | BYTE => byte::validate_byte_node(literal.token(), acc), | ||
29 | BYTE_STRING => byte_string::validate_byte_string_node(literal.token(), acc), | ||
30 | STRING => string::validate_string_node(literal.token(), acc), | ||
31 | CHAR => char::validate_char_node(literal.token(), acc), | ||
32 | _ => (), | ||
33 | } | ||
34 | } | ||
35 | |||
28 | pub(crate) fn validate_block_structure(root: &SyntaxNode) { | 36 | pub(crate) fn validate_block_structure(root: &SyntaxNode) { |
29 | let mut stack = Vec::new(); | 37 | let mut stack = Vec::new(); |
30 | for node in root.descendants() { | 38 | for node in root.descendants() { |
diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs index 838e7a65f..f653e65d0 100644 --- a/crates/ra_syntax/src/validation/byte.rs +++ b/crates/ra_syntax/src/validation/byte.rs | |||
@@ -1,18 +1,18 @@ | |||
1 | //! Validation of byte literals | 1 | //! Validation of byte literals |
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | ast::{self, AstNode, AstToken}, | ||
5 | string_lexing::{self, StringComponentKind}, | 4 | string_lexing::{self, StringComponentKind}, |
6 | TextRange, | 5 | TextRange, |
7 | validation::char, | 6 | validation::char, |
8 | SyntaxError, | 7 | SyntaxError, |
9 | SyntaxErrorKind::*, | 8 | SyntaxErrorKind::*, |
9 | SyntaxToken, | ||
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub(super) fn validate_byte_node(node: &ast::Byte, errors: &mut Vec<SyntaxError>) { | 12 | pub(super) fn validate_byte_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
13 | let literal_text = node.text(); | 13 | let literal_text = node.text(); |
14 | let literal_range = node.syntax().range(); | 14 | let literal_range = node.range(); |
15 | let mut components = string_lexing::parse_byte_literal(literal_text); | 15 | let mut components = string_lexing::parse_quoted_literal(Some('b'), '\'', literal_text); |
16 | let mut len = 0; | 16 | let mut len = 0; |
17 | for component in &mut components { | 17 | for component in &mut components { |
18 | len += 1; | 18 | len += 1; |
diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs index 64c7054a1..1d48c2d9b 100644 --- a/crates/ra_syntax/src/validation/byte_string.rs +++ b/crates/ra_syntax/src/validation/byte_string.rs | |||
@@ -1,16 +1,16 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | ast::{self, AstNode, AstToken}, | ||
3 | string_lexing::{self, StringComponentKind}, | 2 | string_lexing::{self, StringComponentKind}, |
4 | SyntaxError, | 3 | SyntaxError, |
5 | SyntaxErrorKind::*, | 4 | SyntaxErrorKind::*, |
5 | SyntaxToken, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use super::byte; | 8 | use super::byte; |
9 | 9 | ||
10 | pub(crate) fn validate_byte_string_node(node: &ast::ByteString, errors: &mut Vec<SyntaxError>) { | 10 | pub(crate) fn validate_byte_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
11 | let literal_text = node.text(); | 11 | let literal_text = node.text(); |
12 | let literal_range = node.syntax().range(); | 12 | let literal_range = node.range(); |
13 | let mut components = string_lexing::parse_byte_string_literal(literal_text); | 13 | let mut components = string_lexing::parse_quoted_literal(Some('b'), '"', literal_text); |
14 | for component in &mut components { | 14 | for component in &mut components { |
15 | let range = component.range + literal_range.start(); | 15 | let range = component.range + literal_range.start(); |
16 | 16 | ||
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs index c874e5d08..0f1885873 100644 --- a/crates/ra_syntax/src/validation/char.rs +++ b/crates/ra_syntax/src/validation/char.rs | |||
@@ -5,17 +5,17 @@ use std::u32; | |||
5 | use arrayvec::ArrayString; | 5 | use arrayvec::ArrayString; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ast::{self, AstNode, AstToken}, | ||
9 | string_lexing::{self, StringComponentKind}, | 8 | string_lexing::{self, StringComponentKind}, |
10 | TextRange, | 9 | TextRange, |
11 | SyntaxError, | 10 | SyntaxError, |
12 | SyntaxErrorKind::*, | 11 | SyntaxErrorKind::*, |
12 | SyntaxToken, | ||
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(super) fn validate_char_node(node: &ast::Char, errors: &mut Vec<SyntaxError>) { | 15 | pub(super) fn validate_char_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
16 | let literal_text = node.text(); | 16 | let literal_text = node.text(); |
17 | let literal_range = node.syntax().range(); | 17 | let literal_range = node.range(); |
18 | let mut components = string_lexing::parse_char_literal(literal_text); | 18 | let mut components = string_lexing::parse_quoted_literal(None, '\'', literal_text); |
19 | let mut len = 0; | 19 | let mut len = 0; |
20 | for component in &mut components { | 20 | for component in &mut components { |
21 | len += 1; | 21 | len += 1; |
diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs index d857d088c..fc2f1b992 100644 --- a/crates/ra_syntax/src/validation/string.rs +++ b/crates/ra_syntax/src/validation/string.rs | |||
@@ -1,16 +1,16 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | ast::{self, AstNode, AstToken}, | ||
3 | string_lexing, | 2 | string_lexing, |
4 | SyntaxError, | 3 | SyntaxError, |
5 | SyntaxErrorKind::*, | 4 | SyntaxErrorKind::*, |
5 | SyntaxToken, | ||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use super::char; | 8 | use super::char; |
9 | 9 | ||
10 | pub(crate) fn validate_string_node(node: &ast::String, errors: &mut Vec<SyntaxError>) { | 10 | pub(crate) fn validate_string_node(node: SyntaxToken, errors: &mut Vec<SyntaxError>) { |
11 | let literal_text = node.text(); | 11 | let literal_text = node.text(); |
12 | let literal_range = node.syntax().range(); | 12 | let literal_range = node.range(); |
13 | let mut components = string_lexing::parse_string_literal(literal_text); | 13 | let mut components = string_lexing::parse_quoted_literal(None, '"', literal_text); |
14 | for component in &mut components { | 14 | for component in &mut components { |
15 | let range = component.range + literal_range.start(); | 15 | let range = component.range + literal_range.start(); |
16 | 16 | ||