diff options
Diffstat (limited to 'crates/syntax/src/ast/expr_ext.rs')
-rw-r--r-- | crates/syntax/src/ast/expr_ext.rs | 120 |
1 files changed, 18 insertions, 102 deletions
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index 3aff01e83..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 | 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,114 +315,30 @@ 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 | fn find_suffix(text: &str, possible_suffixes: &[&str]) -> Option<SmolStr> { | ||
320 | possible_suffixes | ||
321 | .iter() | ||
322 | .find(|&suffix| text.ends_with(suffix)) | ||
323 | .map(|&suffix| SmolStr::new(suffix)) | ||
324 | } | ||
325 | |||
326 | pub fn kind(&self) -> LiteralKind { | 318 | pub fn kind(&self) -> LiteralKind { |
327 | const INT_SUFFIXES: [&str; 12] = [ | ||
328 | "u64", "u32", "u16", "u8", "usize", "isize", "i64", "i32", "i16", "i8", "u128", "i128", | ||
329 | ]; | ||
330 | const FLOAT_SUFFIXES: [&str; 2] = ["f32", "f64"]; | ||
331 | |||
332 | let token = self.token(); | 319 | let token = self.token(); |
333 | 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 | |||
334 | match token.kind() { | 334 | match token.kind() { |
335 | INT_NUMBER => { | ||
336 | // FYI: there was a bug here previously, thus the if statement below is necessary. | ||
337 | // The lexer treats e.g. `1f64` as an integer literal. See | ||
338 | // https://github.com/rust-analyzer/rust-analyzer/issues/1592 | ||
339 | // and the comments on the linked PR. | ||
340 | |||
341 | let text = token.text(); | ||
342 | if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) { | ||
343 | LiteralKind::FloatNumber { suffix } | ||
344 | } else { | ||
345 | LiteralKind::IntNumber { suffix: Self::find_suffix(&text, &INT_SUFFIXES) } | ||
346 | } | ||
347 | } | ||
348 | FLOAT_NUMBER => { | ||
349 | let text = token.text(); | ||
350 | LiteralKind::FloatNumber { suffix: Self::find_suffix(&text, &FLOAT_SUFFIXES) } | ||
351 | } | ||
352 | STRING | RAW_STRING => LiteralKind::String, | ||
353 | T![true] => LiteralKind::Bool(true), | 335 | T![true] => LiteralKind::Bool(true), |
354 | T![false] => LiteralKind::Bool(false), | 336 | T![false] => LiteralKind::Bool(false), |
355 | BYTE_STRING | RAW_BYTE_STRING => LiteralKind::ByteString, | ||
356 | CHAR => LiteralKind::Char, | 337 | CHAR => LiteralKind::Char, |
357 | BYTE => LiteralKind::Byte, | 338 | BYTE => LiteralKind::Byte, |
358 | _ => unreachable!(), | 339 | _ => unreachable!(), |
359 | } | 340 | } |
360 | } | 341 | } |
361 | |||
362 | // FIXME: should probably introduce string token type? | ||
363 | // https://github.com/rust-analyzer/rust-analyzer/issues/6308 | ||
364 | pub fn int_value(&self) -> Option<(Radix, u128)> { | ||
365 | let suffix = match self.kind() { | ||
366 | LiteralKind::IntNumber { suffix } => suffix, | ||
367 | _ => return None, | ||
368 | }; | ||
369 | |||
370 | let token = self.token(); | ||
371 | let mut text = token.text().as_str(); | ||
372 | text = &text[..text.len() - suffix.map_or(0, |it| it.len())]; | ||
373 | |||
374 | let buf; | ||
375 | if text.contains("_") { | ||
376 | buf = text.replace('_', ""); | ||
377 | text = buf.as_str(); | ||
378 | }; | ||
379 | |||
380 | let radix = Radix::identify(text)?; | ||
381 | let digits = &text[radix.prefix_len()..]; | ||
382 | let value = u128::from_str_radix(digits, radix as u32).ok()?; | ||
383 | Some((radix, value)) | ||
384 | } | ||
385 | } | ||
386 | |||
387 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
388 | pub enum Radix { | ||
389 | Binary = 2, | ||
390 | Octal = 8, | ||
391 | Decimal = 10, | ||
392 | Hexadecimal = 16, | ||
393 | } | ||
394 | |||
395 | impl Radix { | ||
396 | pub const ALL: &'static [Radix] = | ||
397 | &[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal]; | ||
398 | |||
399 | fn identify(literal_text: &str) -> Option<Self> { | ||
400 | // We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible. | ||
401 | if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) { | ||
402 | return Some(Self::Decimal); | ||
403 | } | ||
404 | |||
405 | let res = match &literal_text[..2] { | ||
406 | "0b" => Radix::Binary, | ||
407 | "0o" => Radix::Octal, | ||
408 | "0x" => Radix::Hexadecimal, | ||
409 | _ => Radix::Decimal, | ||
410 | }; | ||
411 | |||
412 | // Checks that all characters after the base prefix are all valid digits for that base. | ||
413 | if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) { | ||
414 | Some(res) | ||
415 | } else { | ||
416 | None | ||
417 | } | ||
418 | } | ||
419 | |||
420 | const fn prefix_len(&self) -> usize { | ||
421 | match self { | ||
422 | Self::Decimal => 0, | ||
423 | _ => 2, | ||
424 | } | ||
425 | } | ||
426 | } | 342 | } |
427 | 343 | ||
428 | #[derive(Debug, Clone, PartialEq, Eq)] | 344 | #[derive(Debug, Clone, PartialEq, Eq)] |