Skip to content

Commit dc09d97

Browse files
bors[bot]Veykril
andauthored
Merge #6649
6649: Accept more than just the standard rust literal suffixes in *Number::suffix r=matklad a=Veykril I am not entirely sure whether to keep or remove the `SUFFIXES` but I figured we can always bring them back once they are needed. Co-authored-by: Lukas Wirth <[email protected]>
2 parents 1db6051 + 49fbfff commit dc09d97

File tree

1 file changed

+55
-22
lines changed

1 file changed

+55
-22
lines changed

crates/syntax/src/ast/token_ext.rs

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -543,11 +543,6 @@ impl HasFormatSpecifier for ast::String {
543543
}
544544

545545
impl 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-
551546
pub fn radix(&self) -> Radix {
552547
match self.text().get(..2).unwrap_or_default() {
553548
"0b" => Radix::Binary,
@@ -580,29 +575,30 @@ impl ast::IntNumber {
580575

581576
pub fn suffix(&self) -> Option<&str> {
582577
let text = self.text();
583-
// FIXME: don't check a fixed set of suffixes, `1_0_1_l_o_l` is valid
584-
// syntax, suffix is `l_o_l`.
585-
ast::IntNumber::SUFFIXES.iter().chain(ast::FloatNumber::SUFFIXES.iter()).find_map(
586-
|suffix| {
587-
if text.ends_with(suffix) {
588-
return Some(&text[text.len() - suffix.len()..]);
589-
}
590-
None
591-
},
592-
)
578+
let radix = self.radix();
579+
let mut indices = text.char_indices();
580+
if radix != Radix::Decimal {
581+
indices.next()?;
582+
indices.next()?;
583+
}
584+
let is_suffix_start: fn(&(usize, char)) -> bool = match radix {
585+
Radix::Hexadecimal => |(_, c)| matches!(c, 'g'..='z' | 'G'..='Z'),
586+
_ => |(_, c)| c.is_ascii_alphabetic(),
587+
};
588+
let (suffix_start, _) = indices.find(is_suffix_start)?;
589+
Some(&text[suffix_start..])
593590
}
594591
}
595592

596593
impl ast::FloatNumber {
597-
const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
598594
pub fn suffix(&self) -> Option<&str> {
599595
let text = self.text();
600-
ast::FloatNumber::SUFFIXES.iter().find_map(|suffix| {
601-
if text.ends_with(suffix) {
602-
return Some(&text[text.len() - suffix.len()..]);
603-
}
604-
None
605-
})
596+
let mut indices = text.char_indices();
597+
let (mut suffix_start, c) = indices.by_ref().find(|(_, c)| c.is_ascii_alphabetic())?;
598+
if c == 'e' || c == 'E' {
599+
suffix_start = indices.find(|(_, c)| c.is_ascii_alphabetic())?.0;
600+
}
601+
Some(&text[suffix_start..])
606602
}
607603
}
608604

@@ -625,3 +621,40 @@ impl Radix {
625621
}
626622
}
627623
}
624+
625+
#[cfg(test)]
626+
mod 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+
}

0 commit comments

Comments
 (0)