diff options
Diffstat (limited to 'crates/syntax')
-rw-r--r-- | crates/syntax/src/ast/expr_ext.rs | 64 | ||||
-rw-r--r-- | crates/syntax/src/ast/token_ext.rs | 32 | ||||
-rw-r--r-- | crates/syntax/src/validation.rs | 57 |
3 files changed, 68 insertions, 85 deletions
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index eb44bb2ab..9253c97d0 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use crate::{ | 3 | use crate::{ |
4 | ast::{self, support, AstChildren, AstNode}, | 4 | ast::{self, support, AstChildren, AstNode}, |
5 | AstToken, SmolStr, | 5 | AstToken, |
6 | SyntaxKind::*, | 6 | SyntaxKind::*, |
7 | SyntaxToken, T, | 7 | SyntaxToken, T, |
8 | }; | 8 | }; |
@@ -298,12 +298,12 @@ impl ast::ArrayExpr { | |||
298 | 298 | ||
299 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 299 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
300 | pub enum LiteralKind { | 300 | pub enum LiteralKind { |
301 | String, | 301 | String(ast::String), |
302 | ByteString, | 302 | ByteString(ast::ByteString), |
303 | IntNumber(ast::IntNumber), | ||
304 | FloatNumber(ast::FloatNumber), | ||
303 | Char, | 305 | Char, |
304 | Byte, | 306 | Byte, |
305 | IntNumber { suffix: Option<SmolStr> }, | ||
306 | FloatNumber { suffix: Option<SmolStr> }, | ||
307 | Bool(bool), | 307 | Bool(bool), |
308 | } | 308 | } |
309 | 309 | ||
@@ -315,53 +315,25 @@ impl ast::Literal { | |||
315 | .and_then(|e| e.into_token()) | 315 | .and_then(|e| e.into_token()) |
316 | .unwrap() | 316 | .unwrap() |
317 | } | 317 | } |
318 | |||
319 | pub fn as_int_number(&self) -> Option<ast::IntNumber> { | ||
320 | ast::IntNumber::cast(self.token()) | ||
321 | } | ||
322 | |||
323 | pub fn as_string(&self) -> Option<ast::String> { | ||
324 | ast::String::cast(self.token()) | ||
325 | } | ||
326 | pub fn as_byte_string(&self) -> Option<ast::ByteString> { | ||
327 | ast::ByteString::cast(self.token()) | ||
328 | } | ||
329 | |||
330 | fn find_suffix(text: &str, possible_suffixes: &[&str]) -> Option<SmolStr> { | ||
331 | possible_suffixes | ||
332 | .iter() | ||
333 | .find(|&suffix| text.ends_with(suffix)) | ||
334 | .map(|&suffix| SmolStr::new(suffix)) | ||
335 | } | ||
336 | |||
337 | pub fn kind(&self) -> LiteralKind { | 318 | pub fn kind(&self) -> LiteralKind { |
338 | let token = self.token(); | 319 | let token = self.token(); |
339 | 320 | ||
321 | if let Some(t) = ast::IntNumber::cast(token.clone()) { | ||
322 | return LiteralKind::IntNumber(t); | ||
323 | } | ||
324 | if let Some(t) = ast::FloatNumber::cast(token.clone()) { | ||
325 | return LiteralKind::FloatNumber(t); | ||
326 | } | ||
327 | if let Some(t) = ast::String::cast(token.clone()) { | ||
328 | return LiteralKind::String(t); | ||
329 | } | ||
330 | if let Some(t) = ast::ByteString::cast(token.clone()) { | ||
331 | return LiteralKind::ByteString(t); | ||
332 | } | ||
333 | |||
340 | match token.kind() { | 334 | match token.kind() { |
341 | INT_NUMBER => { | ||
342 | // FYI: there was a bug here previously, thus the if statement below is necessary. | ||
343 | // The lexer treats e.g. `1f64` as an integer literal. See | ||
344 | // https://github.com/rust-analyzer/rust-analyzer/issues/1592 | ||
345 | // and the comments on the linked PR. | ||
346 | let text = token.text(); | ||
347 | if let suffix @ Some(_) = Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES) { | ||
348 | LiteralKind::FloatNumber { suffix } | ||
349 | } else { | ||
350 | LiteralKind::IntNumber { | ||
351 | suffix: Self::find_suffix(&text, &ast::IntNumber::SUFFIXES), | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | FLOAT_NUMBER => { | ||
356 | let text = token.text(); | ||
357 | LiteralKind::FloatNumber { | ||
358 | suffix: Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES), | ||
359 | } | ||
360 | } | ||
361 | STRING => LiteralKind::String, | ||
362 | T![true] => LiteralKind::Bool(true), | 335 | T![true] => LiteralKind::Bool(true), |
363 | T![false] => LiteralKind::Bool(false), | 336 | T![false] => LiteralKind::Bool(false), |
364 | BYTE_STRING => LiteralKind::ByteString, | ||
365 | CHAR => LiteralKind::Char, | 337 | CHAR => LiteralKind::Char, |
366 | BYTE => LiteralKind::Byte, | 338 | BYTE => LiteralKind::Byte, |
367 | _ => unreachable!(), | 339 | _ => unreachable!(), |
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index bf0035986..e4e512f2e 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -517,10 +517,9 @@ impl HasFormatSpecifier for ast::String { | |||
517 | } | 517 | } |
518 | 518 | ||
519 | impl ast::IntNumber { | 519 | impl ast::IntNumber { |
520 | #[rustfmt::skip] | 520 | const SUFFIXES: &'static [&'static str] = &[ |
521 | pub(crate) const SUFFIXES: &'static [&'static str] = &[ | 521 | "u8", "u16", "u32", "u64", "u128", "usize", // Unsigned. |
522 | "u8", "u16", "u32", "u64", "u128", "usize", | 522 | "i8", "i16", "i32", "i64", "i128", "isize", // Signed. |
523 | "i8", "i16", "i32", "i64", "i128", "isize", | ||
524 | ]; | 523 | ]; |
525 | 524 | ||
526 | pub fn radix(&self) -> Radix { | 525 | pub fn radix(&self) -> Radix { |
@@ -555,9 +554,24 @@ impl ast::IntNumber { | |||
555 | 554 | ||
556 | pub fn suffix(&self) -> Option<&str> { | 555 | pub fn suffix(&self) -> Option<&str> { |
557 | let text = self.text(); | 556 | let text = self.text(); |
558 | // FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid | 557 | // FIXME: don't check a fixed set of suffixes, `1_0_1_l_o_l` is valid |
559 | // syntax, suffix is `lol`. | 558 | // syntax, suffix is `l_o_l`. |
560 | ast::IntNumber::SUFFIXES.iter().find_map(|suffix| { | 559 | ast::IntNumber::SUFFIXES.iter().chain(ast::FloatNumber::SUFFIXES.iter()).find_map( |
560 | |suffix| { | ||
561 | if text.ends_with(suffix) { | ||
562 | return Some(&text[text.len() - suffix.len()..]); | ||
563 | } | ||
564 | None | ||
565 | }, | ||
566 | ) | ||
567 | } | ||
568 | } | ||
569 | |||
570 | impl ast::FloatNumber { | ||
571 | const SUFFIXES: &'static [&'static str] = &["f32", "f64"]; | ||
572 | pub fn suffix(&self) -> Option<&str> { | ||
573 | let text = self.text(); | ||
574 | ast::FloatNumber::SUFFIXES.iter().find_map(|suffix| { | ||
561 | if text.ends_with(suffix) { | 575 | if text.ends_with(suffix) { |
562 | return Some(&text[text.len() - suffix.len()..]); | 576 | return Some(&text[text.len() - suffix.len()..]); |
563 | } | 577 | } |
@@ -566,10 +580,6 @@ impl ast::IntNumber { | |||
566 | } | 580 | } |
567 | } | 581 | } |
568 | 582 | ||
569 | impl ast::FloatNumber { | ||
570 | pub(crate) const SUFFIXES: &'static [&'static str] = &["f32", "f64"]; | ||
571 | } | ||
572 | |||
573 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | 583 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
574 | pub enum Radix { | 584 | pub enum Radix { |
575 | Binary = 2, | 585 | Binary = 2, |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 62a37c50a..6f45149bf 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -4,7 +4,7 @@ mod block; | |||
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | algo, ast, match_ast, AstNode, SyntaxError, | 6 | algo, ast, match_ast, AstNode, SyntaxError, |
7 | SyntaxKind::{BYTE, CHAR, CONST, FN, INT_NUMBER, TYPE_ALIAS}, | 7 | SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS}, |
8 | SyntaxNode, SyntaxToken, TextSize, T, | 8 | SyntaxNode, SyntaxToken, TextSize, T, |
9 | }; | 9 | }; |
10 | use rowan::Direction; | 10 | use rowan::Direction; |
@@ -121,41 +121,42 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { | |||
121 | acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off)); | 121 | acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off)); |
122 | }; | 122 | }; |
123 | 123 | ||
124 | if let Some(s) = literal.as_string() { | 124 | match literal.kind() { |
125 | if !s.is_raw() { | 125 | ast::LiteralKind::String(s) => { |
126 | if let Some(without_quotes) = unquote(text, 1, '"') { | 126 | if !s.is_raw() { |
127 | unescape_literal(without_quotes, Mode::Str, &mut |range, char| { | 127 | if let Some(without_quotes) = unquote(text, 1, '"') { |
128 | if let Err(err) = char { | 128 | unescape_literal(without_quotes, Mode::Str, &mut |range, char| { |
129 | push_err(1, (range.start, err)); | 129 | if let Err(err) = char { |
130 | } | 130 | push_err(1, (range.start, err)); |
131 | }) | 131 | } |
132 | } | 132 | }) |
133 | } | 133 | } |
134 | } | ||
135 | if let Some(s) = literal.as_byte_string() { | ||
136 | if !s.is_raw() { | ||
137 | if let Some(without_quotes) = unquote(text, 2, '"') { | ||
138 | unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| { | ||
139 | if let Err(err) = char { | ||
140 | push_err(2, (range.start, err)); | ||
141 | } | ||
142 | }) | ||
143 | } | 134 | } |
144 | } | 135 | } |
145 | } | 136 | ast::LiteralKind::ByteString(s) => { |
146 | 137 | if !s.is_raw() { | |
147 | match token.kind() { | 138 | if let Some(without_quotes) = unquote(text, 2, '"') { |
148 | BYTE => { | 139 | unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| { |
149 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) { | 140 | if let Err(err) = char { |
150 | push_err(2, e); | 141 | push_err(2, (range.start, err)); |
142 | } | ||
143 | }) | ||
144 | } | ||
151 | } | 145 | } |
152 | } | 146 | } |
153 | CHAR => { | 147 | ast::LiteralKind::Char => { |
154 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) { | 148 | if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) { |
155 | push_err(1, e); | 149 | push_err(1, e); |
156 | } | 150 | } |
157 | } | 151 | } |
158 | _ => (), | 152 | ast::LiteralKind::Byte => { |
153 | if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) { | ||
154 | push_err(2, e); | ||
155 | } | ||
156 | } | ||
157 | ast::LiteralKind::IntNumber(_) | ||
158 | | ast::LiteralKind::FloatNumber(_) | ||
159 | | ast::LiteralKind::Bool(_) => {} | ||
159 | } | 160 | } |
160 | } | 161 | } |
161 | 162 | ||