diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 61 |
1 files changed, 26 insertions, 35 deletions
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 222ac15f8..445e3b3e4 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -111,55 +111,46 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
111 | errors | 111 | errors |
112 | } | 112 | } |
113 | 113 | ||
114 | // FIXME: kill duplication | ||
115 | fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | 114 | fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { |
115 | fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> { | ||
116 | text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end)) | ||
117 | } | ||
118 | |||
116 | let token = literal.token(); | 119 | let token = literal.token(); |
117 | let text = token.text().as_str(); | 120 | let text = token.text().as_str(); |
121 | |||
122 | let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { | ||
123 | let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len); | ||
124 | acc.push(SyntaxError::new(err.into(), off)); | ||
125 | }; | ||
126 | |||
118 | match token.kind() { | 127 | match token.kind() { |
119 | BYTE => { | 128 | BYTE => { |
120 | if let Some(end) = text.rfind('\'') { | 129 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape::unescape_byte) { |
121 | if let Some(without_quotes) = text.get(2..end) { | 130 | push_err(2, e); |
122 | if let Err((off, err)) = unescape::unescape_byte(without_quotes) { | ||
123 | let off = token.text_range().start() + TextUnit::from_usize(off + 2); | ||
124 | acc.push(SyntaxError::new(err.into(), off)) | ||
125 | } | ||
126 | } | ||
127 | } | 131 | } |
128 | } | 132 | } |
129 | CHAR => { | 133 | CHAR => { |
130 | if let Some(end) = text.rfind('\'') { | 134 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape::unescape_char) { |
131 | if let Some(without_quotes) = text.get(1..end) { | 135 | push_err(1, e); |
132 | if let Err((off, err)) = unescape::unescape_char(without_quotes) { | ||
133 | let off = token.text_range().start() + TextUnit::from_usize(off + 1); | ||
134 | acc.push(SyntaxError::new(err.into(), off)) | ||
135 | } | ||
136 | } | ||
137 | } | 136 | } |
138 | } | 137 | } |
139 | BYTE_STRING => { | 138 | BYTE_STRING => { |
140 | if let Some(end) = text.rfind('\"') { | 139 | if let Some(without_quotes) = unquote(text, 2, '"') { |
141 | if let Some(without_quotes) = text.get(2..end) { | 140 | unescape::unescape_byte_str(without_quotes, &mut |range, char| { |
142 | unescape::unescape_byte_str(without_quotes, &mut |range, char| { | 141 | if let Err(err) = char { |
143 | if let Err(err) = char { | 142 | push_err(2, (range.start, err)); |
144 | let off = range.start; | 143 | } |
145 | let off = token.text_range().start() + TextUnit::from_usize(off + 2); | 144 | }) |
146 | acc.push(SyntaxError::new(err.into(), off)) | ||
147 | } | ||
148 | }) | ||
149 | } | ||
150 | } | 145 | } |
151 | } | 146 | } |
152 | STRING => { | 147 | STRING => { |
153 | if let Some(end) = text.rfind('\"') { | 148 | if let Some(without_quotes) = unquote(text, 1, '"') { |
154 | if let Some(without_quotes) = text.get(1..end) { | 149 | unescape::unescape_str(without_quotes, &mut |range, char| { |
155 | unescape::unescape_str(without_quotes, &mut |range, char| { | 150 | if let Err(err) = char { |
156 | if let Err(err) = char { | 151 | push_err(1, (range.start, err)); |
157 | let off = range.start; | 152 | } |
158 | let off = token.text_range().start() + TextUnit::from_usize(off + 1); | 153 | }) |
159 | acc.push(SyntaxError::new(err.into(), off)) | ||
160 | } | ||
161 | }) | ||
162 | } | ||
163 | } | 154 | } |
164 | } | 155 | } |
165 | _ => (), | 156 | _ => (), |