diff options
Diffstat (limited to 'crates/ra_syntax/src/ast/tokens.rs')
-rw-r--r-- | crates/ra_syntax/src/ast/tokens.rs | 113 |
1 files changed, 113 insertions, 0 deletions
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 | } | ||