aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast/tokens.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast/tokens.rs')
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs95
1 files changed, 85 insertions, 10 deletions
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 87cca325d..ed8661faf 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -2,8 +2,8 @@
2 2
3use crate::{ 3use crate::{
4 ast::AstToken, 4 ast::AstToken,
5 SyntaxKind::{COMMENT, WHITESPACE}, 5 SyntaxKind::{COMMENT, RAW_STRING, STRING, WHITESPACE},
6 SyntaxToken, 6 SyntaxToken, TextRange, TextUnit,
7}; 7};
8 8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)] 9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -11,10 +11,9 @@ pub struct Comment(SyntaxToken);
11 11
12impl AstToken for Comment { 12impl AstToken for Comment {
13 fn cast(token: SyntaxToken) -> Option<Self> { 13 fn cast(token: SyntaxToken) -> Option<Self> {
14 if token.kind() == COMMENT { 14 match token.kind() {
15 Some(Comment(token)) 15 COMMENT => Some(Comment(token)),
16 } else { 16 _ => None,
17 None
18 } 17 }
19 } 18 }
20 fn syntax(&self) -> &SyntaxToken { 19 fn syntax(&self) -> &SyntaxToken {
@@ -94,10 +93,9 @@ pub struct Whitespace(SyntaxToken);
94 93
95impl AstToken for Whitespace { 94impl AstToken for Whitespace {
96 fn cast(token: SyntaxToken) -> Option<Self> { 95 fn cast(token: SyntaxToken) -> Option<Self> {
97 if token.kind() == WHITESPACE { 96 match token.kind() {
98 Some(Whitespace(token)) 97 WHITESPACE => Some(Whitespace(token)),
99 } else { 98 _ => None,
100 None
101 } 99 }
102 } 100 }
103 fn syntax(&self) -> &SyntaxToken { 101 fn syntax(&self) -> &SyntaxToken {
@@ -111,3 +109,80 @@ impl Whitespace {
111 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) 109 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
112 } 110 }
113} 111}
112
113pub struct String(SyntaxToken);
114
115impl AstToken for String {
116 fn cast(token: SyntaxToken) -> Option<Self> {
117 match token.kind() {
118 STRING => Some(String(token)),
119 _ => None,
120 }
121 }
122 fn syntax(&self) -> &SyntaxToken {
123 &self.0
124 }
125}
126
127impl String {
128 pub fn value(&self) -> Option<std::string::String> {
129 let text = self.text().as_str();
130 let usual_string_range = find_usual_string_range(text)?;
131 let start_of_inside = usual_string_range.start().to_usize() + 1;
132 let end_of_inside = usual_string_range.end().to_usize();
133 let inside_str = &text[start_of_inside..end_of_inside];
134
135 let mut buf = std::string::String::with_capacity(inside_str.len());
136 let mut has_error = false;
137 rustc_lexer::unescape::unescape_str(inside_str, &mut |_, unescaped_char| {
138 match unescaped_char {
139 Ok(c) => buf.push(c),
140 Err(_) => has_error = true,
141 }
142 });
143
144 if has_error {
145 return None;
146 }
147 Some(buf)
148 }
149}
150
151pub struct RawString(SyntaxToken);
152
153impl AstToken for RawString {
154 fn cast(token: SyntaxToken) -> Option<Self> {
155 match token.kind() {
156 RAW_STRING => Some(RawString(token)),
157 _ => None,
158 }
159 }
160 fn syntax(&self) -> &SyntaxToken {
161 &self.0
162 }
163}
164
165impl RawString {
166 pub fn value(&self) -> Option<std::string::String> {
167 let text = self.text().as_str();
168 let usual_string_range = find_usual_string_range(text)?;
169 let start_of_inside = usual_string_range.start().to_usize() + 1;
170 let end_of_inside = usual_string_range.end().to_usize();
171 let inside_str = &text[start_of_inside..end_of_inside];
172 Some(inside_str.to_string())
173 }
174}
175
176fn find_usual_string_range(s: &str) -> Option<TextRange> {
177 let left_quote = s.find('"')?;
178 let right_quote = s.rfind('"')?;
179 if left_quote == right_quote {
180 // `s` only contains one quote
181 None
182 } else {
183 Some(TextRange::from_to(
184 TextUnit::from(left_quote as u32),
185 TextUnit::from(right_quote as u32),
186 ))
187 }
188}