aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src')
-rw-r--r--crates/syntax/src/ast/expr_ext.rs64
-rw-r--r--crates/syntax/src/ast/token_ext.rs32
-rw-r--r--crates/syntax/src/validation.rs57
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
3use crate::{ 3use 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)]
300pub enum LiteralKind { 300pub 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
519impl ast::IntNumber { 519impl 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
570impl 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
569impl 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)]
574pub enum Radix { 584pub 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
5use crate::{ 5use 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};
10use rowan::Direction; 10use 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