aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/syntax/src/ast/token_ext.rs77
1 files changed, 55 insertions, 22 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index b985861f2..fa40e64e8 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -543,11 +543,6 @@ impl HasFormatSpecifier for ast::String {
543} 543}
544 544
545impl ast::IntNumber { 545impl ast::IntNumber {
546 const SUFFIXES: &'static [&'static str] = &[
547 "u8", "u16", "u32", "u64", "u128", "usize", // Unsigned.
548 "i8", "i16", "i32", "i64", "i128", "isize", // Signed.
549 ];
550
551 pub fn radix(&self) -> Radix { 546 pub fn radix(&self) -> Radix {
552 match self.text().get(..2).unwrap_or_default() { 547 match self.text().get(..2).unwrap_or_default() {
553 "0b" => Radix::Binary, 548 "0b" => Radix::Binary,
@@ -580,29 +575,30 @@ impl ast::IntNumber {
580 575
581 pub fn suffix(&self) -> Option<&str> { 576 pub fn suffix(&self) -> Option<&str> {
582 let text = self.text(); 577 let text = self.text();
583 // FIXME: don't check a fixed set of suffixes, `1_0_1_l_o_l` is valid 578 let radix = self.radix();
584 // syntax, suffix is `l_o_l`. 579 let mut indices = text.char_indices();
585 ast::IntNumber::SUFFIXES.iter().chain(ast::FloatNumber::SUFFIXES.iter()).find_map( 580 if radix != Radix::Decimal {
586 |suffix| { 581 indices.next()?;
587 if text.ends_with(suffix) { 582 indices.next()?;
588 return Some(&text[text.len() - suffix.len()..]); 583 }
589 } 584 let is_suffix_start: fn(&(usize, char)) -> bool = match radix {
590 None 585 Radix::Hexadecimal => |(_, c)| matches!(c, 'g'..='z' | 'G'..='Z'),
591 }, 586 _ => |(_, c)| c.is_ascii_alphabetic(),
592 ) 587 };
588 let (suffix_start, _) = indices.find(is_suffix_start)?;
589 Some(&text[suffix_start..])
593 } 590 }
594} 591}
595 592
596impl ast::FloatNumber { 593impl ast::FloatNumber {
597 const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
598 pub fn suffix(&self) -> Option<&str> { 594 pub fn suffix(&self) -> Option<&str> {
599 let text = self.text(); 595 let text = self.text();
600 ast::FloatNumber::SUFFIXES.iter().find_map(|suffix| { 596 let mut indices = text.char_indices();
601 if text.ends_with(suffix) { 597 let (mut suffix_start, c) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())?;
602 return Some(&text[text.len() - suffix.len()..]); 598 if c == 'e' || c == 'E' {
603 } 599 suffix_start = indices.find(|(_, c)| c.is_ascii_alphabetic())?.0;
604 None 600 }
605 }) 601 Some(&text[suffix_start..])
606 } 602 }
607} 603}
608 604
@@ -625,3 +621,40 @@ impl Radix {
625 } 621 }
626 } 622 }
627} 623}
624
625#[cfg(test)]
626mod tests {
627 use crate::ast::{make, FloatNumber, IntNumber};
628
629 fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
630 assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
631 }
632
633 fn check_int_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
634 assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
635 }
636
637 #[test]
638 fn test_float_number_suffix() {
639 check_float_suffix("123.0", None);
640 check_float_suffix("123f32", "f32");
641 check_float_suffix("123.0e", None);
642 check_float_suffix("123.0e4", None);
643 check_float_suffix("123.0ef32", "f32");
644 check_float_suffix("123.0E4f32", "f32");
645 check_float_suffix("1_2_3.0_f32", "f32");
646 }
647
648 #[test]
649 fn test_int_number_suffix() {
650 check_int_suffix("123", None);
651 check_int_suffix("123i32", "i32");
652 check_int_suffix("1_0_1_l_o_l", "l_o_l");
653 check_int_suffix("0b11", None);
654 check_int_suffix("0o11", None);
655 check_int_suffix("0xff", None);
656 check_int_suffix("0b11u32", "u32");
657 check_int_suffix("0o11u32", "u32");
658 check_int_suffix("0xffu32", "u32");
659 }
660}