aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-04-02 11:02:48 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-04-02 11:02:48 +0100
commitb0d244719323d68905986857844f56d1fa38cac4 (patch)
tree32ae51ee2d96c526bcfb9eb3f3a8adf18aca39c6 /crates/ra_syntax
parent370dbc7867719662f26db5684ac82cfc25b5b8cb (diff)
parentab19ff16e55d4d64445fc2809e52d913ad492040 (diff)
Merge #1088
1088: add minimal comments r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast.rs567
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs252
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs303
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs2
-rw-r--r--crates/ra_syntax/src/ast/traits.rs4
5 files changed, 579 insertions, 549 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index beef2c6e2..9f5c41b0c 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -1,22 +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
2mod generated; 3mod generated;
3mod traits; 4mod traits;
4mod tokens; 5mod tokens;
6mod extensions;
7mod expr_extensions;
5 8
6use std::marker::PhantomData; 9use std::marker::PhantomData;
7 10
8use itertools::Itertools;
9
10use crate::{ 11use crate::{
11 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement}, 12 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken},
12 SmolStr, 13 SmolStr,
13 SyntaxKind::*,
14}; 14};
15 15
16pub use self::{ 16pub use self::{
17 generated::*, 17 generated::*,
18 traits::*, 18 traits::*,
19 tokens::*, 19 tokens::*,
20 extensions::{PathSegmentKind, StructKind, SelfParamKind},
21 expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind},
20}; 22};
21 23
22/// 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
@@ -32,6 +34,18 @@ pub trait AstNode:
32 fn syntax(&self) -> &SyntaxNode; 34 fn syntax(&self) -> &SyntaxNode;
33} 35}
34 36
37/// Like `AstNode`, but wraps tokens rather than interior nodes.
38pub trait AstToken<'a> {
39 fn cast(token: SyntaxToken<'a>) -> Option<Self>
40 where
41 Self: Sized;
42 fn syntax(&self) -> SyntaxToken<'a>;
43 fn text(&self) -> &'a SmolStr {
44 self.syntax().text()
45 }
46}
47
48/// An iterator over `SyntaxNode` children of a particular AST type.
35#[derive(Debug)] 49#[derive(Debug)]
36pub struct AstChildren<'a, N> { 50pub struct AstChildren<'a, N> {
37 inner: SyntaxNodeChildren<'a>, 51 inner: SyntaxNodeChildren<'a>,
@@ -51,215 +65,6 @@ impl<'a, N: AstNode + 'a> Iterator for AstChildren<'a, N> {
51 } 65 }
52} 66}
53 67
54pub trait AstToken<'a> {
55 fn cast(token: SyntaxToken<'a>) -> Option<Self>
56 where
57 Self: Sized;
58 fn syntax(&self) -> SyntaxToken<'a>;
59 fn text(&self) -> &'a SmolStr {
60 self.syntax().text()
61 }
62}
63
64impl Attr {
65 pub fn is_inner(&self) -> bool {
66 let tt = match self.value() {
67 None => return false,
68 Some(tt) => tt,
69 };
70
71 let prev = match tt.syntax().prev_sibling() {
72 None => return false,
73 Some(prev) => prev,
74 };
75
76 prev.kind() == EXCL
77 }
78
79 pub fn as_atom(&self) -> Option<SmolStr> {
80 let tt = self.value()?;
81 let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
82 if attr.kind() == IDENT {
83 Some(attr.as_token()?.text().clone())
84 } else {
85 None
86 }
87 }
88
89 pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> {
90 let tt = self.value()?;
91 let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
92 let args = TokenTree::cast(args.as_node()?)?;
93 if attr.kind() == IDENT {
94 Some((attr.as_token()?.text().clone(), args))
95 } else {
96 None
97 }
98 }
99
100 pub fn as_named(&self) -> Option<SmolStr> {
101 let tt = self.value()?;
102 let attr = tt.syntax().children_with_tokens().nth(1)?;
103 if attr.kind() == IDENT {
104 Some(attr.as_token()?.text().clone())
105 } else {
106 None
107 }
108 }
109}
110
111impl Name {
112 pub fn text(&self) -> &SmolStr {
113 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
114 ident.text()
115 }
116}
117
118impl NameRef {
119 pub fn text(&self) -> &SmolStr {
120 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
121 ident.text()
122 }
123}
124
125impl ImplBlock {
126 pub fn target_type(&self) -> Option<&TypeRef> {
127 match self.target() {
128 (Some(t), None) | (_, Some(t)) => Some(t),
129 _ => None,
130 }
131 }
132
133 pub fn target_trait(&self) -> Option<&TypeRef> {
134 match self.target() {
135 (Some(t), Some(_)) => Some(t),
136 _ => None,
137 }
138 }
139
140 fn target(&self) -> (Option<&TypeRef>, Option<&TypeRef>) {
141 let mut types = children(self);
142 let first = types.next();
143 let second = types.next();
144 (first, second)
145 }
146}
147
148impl Module {
149 pub fn has_semi(&self) -> bool {
150 match self.syntax().last_child_or_token() {
151 None => false,
152 Some(node) => node.kind() == SEMI,
153 }
154 }
155}
156
157impl LetStmt {
158 pub fn has_semi(&self) -> bool {
159 match self.syntax().last_child_or_token() {
160 None => false,
161 Some(node) => node.kind() == SEMI,
162 }
163 }
164}
165
166#[derive(Debug, Clone, PartialEq, Eq)]
167pub enum ElseBranchFlavor<'a> {
168 Block(&'a Block),
169 IfExpr(&'a IfExpr),
170}
171
172impl IfExpr {
173 pub fn then_branch(&self) -> Option<&Block> {
174 self.blocks().nth(0)
175 }
176 pub fn else_branch(&self) -> Option<ElseBranchFlavor> {
177 let res = match self.blocks().nth(1) {
178 Some(block) => ElseBranchFlavor::Block(block),
179 None => {
180 let elif: &IfExpr = child_opt(self)?;
181 ElseBranchFlavor::IfExpr(elif)
182 }
183 };
184 Some(res)
185 }
186
187 fn blocks(&self) -> AstChildren<Block> {
188 children(self)
189 }
190}
191
192impl ExprStmt {
193 pub fn has_semi(&self) -> bool {
194 match self.syntax().last_child_or_token() {
195 None => false,
196 Some(node) => node.kind() == SEMI,
197 }
198 }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub enum PathSegmentKind<'a> {
203 Name(&'a NameRef),
204 SelfKw,
205 SuperKw,
206 CrateKw,
207}
208
209impl PathSegment {
210 pub fn parent_path(&self) -> &Path {
211 self.syntax().parent().and_then(Path::cast).expect("segments are always nested in paths")
212 }
213
214 pub fn kind(&self) -> Option<PathSegmentKind> {
215 let res = if let Some(name_ref) = self.name_ref() {
216 PathSegmentKind::Name(name_ref)
217 } else {
218 match self.syntax().first_child_or_token()?.kind() {
219 SELF_KW => PathSegmentKind::SelfKw,
220 SUPER_KW => PathSegmentKind::SuperKw,
221 CRATE_KW => PathSegmentKind::CrateKw,
222 _ => return None,
223 }
224 };
225 Some(res)
226 }
227
228 pub fn has_colon_colon(&self) -> bool {
229 match self.syntax.first_child_or_token().map(|s| s.kind()) {
230 Some(COLONCOLON) => true,
231 _ => false,
232 }
233 }
234}
235
236impl Path {
237 pub fn parent_path(&self) -> Option<&Path> {
238 self.syntax().parent().and_then(Path::cast)
239 }
240}
241
242impl UseTree {
243 pub fn has_star(&self) -> bool {
244 self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
245 }
246}
247
248impl UseTreeList {
249 pub fn parent_use_tree(&self) -> &UseTree {
250 self.syntax()
251 .parent()
252 .and_then(UseTree::cast)
253 .expect("UseTreeLists are always nested in UseTrees")
254 }
255}
256
257impl RefPat {
258 pub fn is_mut(&self) -> bool {
259 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
260 }
261}
262
263fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { 68fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> {
264 children(parent).next() 69 children(parent).next()
265} 70}
@@ -268,342 +73,6 @@ fn children<P: AstNode, C: AstNode>(parent: &P) -> AstChildren<C> {
268 AstChildren::new(parent.syntax()) 73 AstChildren::new(parent.syntax())
269} 74}
270 75
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub enum StructFlavor<'a> {
273 Tuple(&'a PosFieldDefList),
274 Named(&'a NamedFieldDefList),
275 Unit,
276}
277
278impl StructFlavor<'_> {
279 fn from_node<N: AstNode>(node: &N) -> StructFlavor {
280 if let Some(nfdl) = child_opt::<_, NamedFieldDefList>(node) {
281 StructFlavor::Named(nfdl)
282 } else if let Some(pfl) = child_opt::<_, PosFieldDefList>(node) {
283 StructFlavor::Tuple(pfl)
284 } else {
285 StructFlavor::Unit
286 }
287 }
288}
289
290impl StructDef {
291 pub fn flavor(&self) -> StructFlavor {
292 StructFlavor::from_node(self)
293 }
294}
295
296impl EnumVariant {
297 pub fn parent_enum(&self) -> &EnumDef {
298 self.syntax()
299 .parent()
300 .and_then(|it| it.parent())
301 .and_then(EnumDef::cast)
302 .expect("EnumVariants are always nested in Enums")
303 }
304 pub fn flavor(&self) -> StructFlavor {
305 StructFlavor::from_node(self)
306 }
307}
308
309impl PointerType {
310 pub fn is_mut(&self) -> bool {
311 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
312 }
313}
314
315impl ReferenceType {
316 pub fn is_mut(&self) -> bool {
317 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
318 }
319}
320
321impl RefExpr {
322 pub fn is_mut(&self) -> bool {
323 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
324 }
325}
326
327#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
328pub enum PrefixOp {
329 /// The `*` operator for dereferencing
330 Deref,
331 /// The `!` operator for logical inversion
332 Not,
333 /// The `-` operator for negation
334 Neg,
335}
336
337impl PrefixExpr {
338 pub fn op_kind(&self) -> Option<PrefixOp> {
339 match self.op_token()?.kind() {
340 STAR => Some(PrefixOp::Deref),
341 EXCL => Some(PrefixOp::Not),
342 MINUS => Some(PrefixOp::Neg),
343 _ => None,
344 }
345 }
346
347 pub fn op_token(&self) -> Option<SyntaxToken> {
348 self.syntax().first_child_or_token()?.as_token()
349 }
350}
351
352#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
353pub enum BinOp {
354 /// The `||` operator for boolean OR
355 BooleanOr,
356 /// The `&&` operator for boolean AND
357 BooleanAnd,
358 /// The `==` operator for equality testing
359 EqualityTest,
360 /// The `!=` operator for equality testing
361 NegatedEqualityTest,
362 /// The `<=` operator for lesser-equal testing
363 LesserEqualTest,
364 /// The `>=` operator for greater-equal testing
365 GreaterEqualTest,
366 /// The `<` operator for comparison
367 LesserTest,
368 /// The `>` operator for comparison
369 GreaterTest,
370 /// The `+` operator for addition
371 Addition,
372 /// The `*` operator for multiplication
373 Multiplication,
374 /// The `-` operator for subtraction
375 Subtraction,
376 /// The `/` operator for division
377 Division,
378 /// The `%` operator for remainder after division
379 Remainder,
380 /// The `<<` operator for left shift
381 LeftShift,
382 /// The `>>` operator for right shift
383 RightShift,
384 /// The `^` operator for bitwise XOR
385 BitwiseXor,
386 /// The `|` operator for bitwise OR
387 BitwiseOr,
388 /// The `&` operator for bitwise AND
389 BitwiseAnd,
390 /// The `..` operator for right-open ranges
391 RangeRightOpen,
392 /// The `..=` operator for right-closed ranges
393 RangeRightClosed,
394 /// The `=` operator for assignment
395 Assignment,
396 /// The `+=` operator for assignment after addition
397 AddAssign,
398 /// The `/=` operator for assignment after division
399 DivAssign,
400 /// The `*=` operator for assignment after multiplication
401 MulAssign,
402 /// The `%=` operator for assignment after remainders
403 RemAssign,
404 /// The `>>=` operator for assignment after shifting right
405 ShrAssign,
406 /// The `<<=` operator for assignment after shifting left
407 ShlAssign,
408 /// The `-=` operator for assignment after subtraction
409 SubAssign,
410 /// The `|=` operator for assignment after bitwise OR
411 BitOrAssign,
412 /// The `&=` operator for assignment after bitwise AND
413 BitAndAssign,
414 /// The `^=` operator for assignment after bitwise XOR
415 BitXorAssign,
416}
417
418impl BinExpr {
419 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
420 self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| {
421 match c.kind() {
422 PIPEPIPE => Some((c, BinOp::BooleanOr)),
423 AMPAMP => Some((c, BinOp::BooleanAnd)),
424 EQEQ => Some((c, BinOp::EqualityTest)),
425 NEQ => Some((c, BinOp::NegatedEqualityTest)),
426 LTEQ => Some((c, BinOp::LesserEqualTest)),
427 GTEQ => Some((c, BinOp::GreaterEqualTest)),
428 L_ANGLE => Some((c, BinOp::LesserTest)),
429 R_ANGLE => Some((c, BinOp::GreaterTest)),
430 PLUS => Some((c, BinOp::Addition)),
431 STAR => Some((c, BinOp::Multiplication)),
432 MINUS => Some((c, BinOp::Subtraction)),
433 SLASH => Some((c, BinOp::Division)),
434 PERCENT => Some((c, BinOp::Remainder)),
435 SHL => Some((c, BinOp::LeftShift)),
436 SHR => Some((c, BinOp::RightShift)),
437 CARET => Some((c, BinOp::BitwiseXor)),
438 PIPE => Some((c, BinOp::BitwiseOr)),
439 AMP => Some((c, BinOp::BitwiseAnd)),
440 DOTDOT => Some((c, BinOp::RangeRightOpen)),
441 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
442 EQ => Some((c, BinOp::Assignment)),
443 PLUSEQ => Some((c, BinOp::AddAssign)),
444 SLASHEQ => Some((c, BinOp::DivAssign)),
445 STAREQ => Some((c, BinOp::MulAssign)),
446 PERCENTEQ => Some((c, BinOp::RemAssign)),
447 SHREQ => Some((c, BinOp::ShrAssign)),
448 SHLEQ => Some((c, BinOp::ShlAssign)),
449 MINUSEQ => Some((c, BinOp::SubAssign)),
450 PIPEEQ => Some((c, BinOp::BitOrAssign)),
451 AMPEQ => Some((c, BinOp::BitAndAssign)),
452 CARETEQ => Some((c, BinOp::BitXorAssign)),
453 _ => None,
454 }
455 })
456 }
457
458 pub fn op_kind(&self) -> Option<BinOp> {
459 self.op_details().map(|t| t.1)
460 }
461
462 pub fn op_token(&self) -> Option<SyntaxToken> {
463 self.op_details().map(|t| t.0)
464 }
465
466 pub fn lhs(&self) -> Option<&Expr> {
467 children(self).nth(0)
468 }
469
470 pub fn rhs(&self) -> Option<&Expr> {
471 children(self).nth(1)
472 }
473
474 pub fn sub_exprs(&self) -> (Option<&Expr>, Option<&Expr>) {
475 let mut children = children(self);
476 let first = children.next();
477 let second = children.next();
478 (first, second)
479 }
480}
481
482#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
483pub enum SelfParamFlavor {
484 /// self
485 Owned,
486 /// &self
487 Ref,
488 /// &mut self
489 MutRef,
490}
491
492impl SelfParam {
493 pub fn self_kw_token(&self) -> SyntaxToken {
494 self.syntax()
495 .children_with_tokens()
496 .filter_map(|it| it.as_token())
497 .find(|it| it.kind() == SELF_KW)
498 .expect("invalid tree: self param must have self")
499 }
500
501 pub fn flavor(&self) -> SelfParamFlavor {
502 let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP);
503 if borrowed {
504 // check for a `mut` coming after the & -- `mut &self` != `&mut self`
505 if self
506 .syntax()
507 .children_with_tokens()
508 .skip_while(|n| n.kind() != AMP)
509 .any(|n| n.kind() == MUT_KW)
510 {
511 SelfParamFlavor::MutRef
512 } else {
513 SelfParamFlavor::Ref
514 }
515 } else {
516 SelfParamFlavor::Owned
517 }
518 }
519}
520
521#[derive(Clone, Debug, PartialEq, Eq, Hash)]
522pub enum LiteralFlavor {
523 String,
524 ByteString,
525 Char,
526 Byte,
527 IntNumber { suffix: Option<SmolStr> },
528 FloatNumber { suffix: Option<SmolStr> },
529 Bool,
530}
531
532impl Literal {
533 pub fn token(&self) -> SyntaxToken {
534 match self.syntax().first_child_or_token().unwrap() {
535 SyntaxElement::Token(token) => token,
536 _ => unreachable!(),
537 }
538 }
539
540 pub fn flavor(&self) -> LiteralFlavor {
541 match self.token().kind() {
542 INT_NUMBER => {
543 let allowed_suffix_list = [
544 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
545 "u16", "u8",
546 ];
547 let text = self.token().text().to_string();
548 let suffix = allowed_suffix_list
549 .iter()
550 .find(|&s| text.ends_with(s))
551 .map(|&suf| SmolStr::new(suf));
552 LiteralFlavor::IntNumber { suffix }
553 }
554 FLOAT_NUMBER => {
555 let allowed_suffix_list = ["f64", "f32"];
556 let text = self.token().text().to_string();
557 let suffix = allowed_suffix_list
558 .iter()
559 .find(|&s| text.ends_with(s))
560 .map(|&suf| SmolStr::new(suf));
561 LiteralFlavor::FloatNumber { suffix: suffix }
562 }
563 STRING | RAW_STRING => LiteralFlavor::String,
564 TRUE_KW | FALSE_KW => LiteralFlavor::Bool,
565 BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString,
566 CHAR => LiteralFlavor::Char,
567 BYTE => LiteralFlavor::Byte,
568 _ => unreachable!(),
569 }
570 }
571}
572
573impl NamedField {
574 pub fn parent_struct_lit(&self) -> &StructLit {
575 self.syntax().ancestors().find_map(StructLit::cast).unwrap()
576 }
577}
578
579impl BindPat {
580 pub fn is_mutable(&self) -> bool {
581 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
582 }
583
584 pub fn is_ref(&self) -> bool {
585 self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW)
586 }
587}
588
589impl LifetimeParam {
590 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
591 self.syntax()
592 .children_with_tokens()
593 .filter_map(|it| it.as_token())
594 .find(|it| it.kind() == LIFETIME)
595 }
596}
597
598impl WherePred {
599 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
600 self.syntax()
601 .children_with_tokens()
602 .filter_map(|it| it.as_token())
603 .find(|it| it.kind() == LIFETIME)
604 }
605}
606
607#[test] 76#[test]
608fn test_doc_comment_none() { 77fn test_doc_comment_none() {
609 let file = SourceFile::parse( 78 let file = SourceFile::parse(
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
3use crate::{
4 SyntaxToken, SyntaxElement, SmolStr,
5 ast::{self, AstNode, AstChildren, children, child_opt},
6 SyntaxKind::*
7};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum ElseBranch<'a> {
11 Block(&'a ast::Block),
12 IfExpr(&'a ast::IfExpr),
13}
14
15impl 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
35impl 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)]
42pub 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
51impl 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)]
67pub 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
132impl 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)]
197pub enum LiteralKind {
198 String,
199 ByteString,
200 Char,
201 Byte,
202 IntNumber { suffix: Option<SmolStr> },
203 FloatNumber { suffix: Option<SmolStr> },
204 Bool,
205}
206
207impl 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
248impl 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
4use itertools::Itertools;
5
6use crate::{
7 SmolStr, SyntaxToken,
8 ast::{self, AstNode, children, child_opt},
9 SyntaxKind::*,
10};
11
12impl 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
19impl 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
26impl 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)]
74pub enum PathSegmentKind<'a> {
75 Name(&'a ast::NameRef),
76 SelfKw,
77 SuperKw,
78 CrateKw,
79}
80
81impl 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
111impl ast::Path {
112 pub fn parent_path(&self) -> Option<&ast::Path> {
113 self.syntax().parent().and_then(ast::Path::cast)
114 }
115}
116
117impl 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
126impl ast::UseTree {
127 pub fn has_star(&self) -> bool {
128 self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
129 }
130}
131
132impl 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
141impl 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)]
165pub enum StructKind<'a> {
166 Tuple(&'a ast::PosFieldDefList),
167 Named(&'a ast::NamedFieldDefList),
168 Unit,
169}
170
171impl 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
183impl ast::StructDef {
184 pub fn kind(&self) -> StructKind {
185 StructKind::from_node(self)
186 }
187}
188
189impl 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
202impl 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
211impl 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
220impl ast::RefPat {
221 pub fn is_mut(&self) -> bool {
222 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
223 }
224}
225
226impl 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
236impl ast::PointerType {
237 pub fn is_mut(&self) -> bool {
238 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
239 }
240}
241
242impl 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)]
249pub enum SelfParamKind {
250 /// self
251 Owned,
252 /// &self
253 Ref,
254 /// &mut self
255 MutRef,
256}
257
258impl 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
287impl 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
296impl 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/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 7c30ff15c..da7d507bf 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -1,3 +1,5 @@
1//! There are many AstNodes, but only a few tokens, so we hand-write them here.
2
1use crate::{ 3use crate::{
2 SyntaxToken, 4 SyntaxToken,
3 SyntaxKind::{COMMENT, WHITESPACE}, 5 SyntaxKind::{COMMENT, WHITESPACE},
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs
index 98aa22085..aaf07d731 100644
--- a/crates/ra_syntax/src/ast/traits.rs
+++ b/crates/ra_syntax/src/ast/traits.rs
@@ -1,3 +1,7 @@
1//! Various traits that are implemented by ast nodes.
2//!
3//! The implementations are usually trivial, and live in generated.rs
4
1use itertools::Itertools; 5use itertools::Itertools;
2 6
3use crate::{ 7use crate::{