aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/ast/token_ext.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-11-06 17:54:01 +0000
committerAleksey Kladov <[email protected]>2020-11-06 17:54:01 +0000
commit735aaa7b39b4d3d789ad75c167bbf322a65ca257 (patch)
tree865daba83547042e2aed9cc412382fd646a5a158 /crates/syntax/src/ast/token_ext.rs
parent6bcc33e5b7e32a79865be4893fcc33caf8d831d6 (diff)
Move int parsing to IntNumber token
Diffstat (limited to 'crates/syntax/src/ast/token_ext.rs')
-rw-r--r--crates/syntax/src/ast/token_ext.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 44f967acb..5623799b4 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -536,3 +536,81 @@ impl HasFormatSpecifier for ast::RawString {
536 Some(res) 536 Some(res)
537 } 537 }
538} 538}
539
540impl ast::IntNumber {
541 #[rustfmt::skip]
542 pub(crate) const SUFFIXES: &'static [&'static str] = &[
543 "u8", "u16", "u32", "u64", "u128", "usize",
544 "i8", "i16", "i32", "i64", "i128", "isize",
545 ];
546
547 // FIXME: should probably introduce string token type?
548 // https://github.com/rust-analyzer/rust-analyzer/issues/6308
549 pub fn value(&self) -> Option<(Radix, u128)> {
550 let token = self.syntax();
551
552 let mut text = token.text().as_str();
553 for suffix in ast::IntNumber::SUFFIXES {
554 if let Some(without_suffix) = text.strip_suffix(suffix) {
555 text = without_suffix;
556 break;
557 }
558 }
559
560 let buf;
561 if text.contains("_") {
562 buf = text.replace('_', "");
563 text = buf.as_str();
564 };
565
566 let radix = Radix::identify(text)?;
567 let digits = &text[radix.prefix_len()..];
568 let value = u128::from_str_radix(digits, radix as u32).ok()?;
569 Some((radix, value))
570 }
571}
572
573impl ast::FloatNumber {
574 pub(crate) const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
575}
576
577#[derive(Debug, PartialEq, Eq, Copy, Clone)]
578pub enum Radix {
579 Binary = 2,
580 Octal = 8,
581 Decimal = 10,
582 Hexadecimal = 16,
583}
584
585impl Radix {
586 pub const ALL: &'static [Radix] =
587 &[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
588
589 fn identify(literal_text: &str) -> Option<Self> {
590 // We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible.
591 if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) {
592 return Some(Self::Decimal);
593 }
594
595 let res = match &literal_text[..2] {
596 "0b" => Radix::Binary,
597 "0o" => Radix::Octal,
598 "0x" => Radix::Hexadecimal,
599 _ => Radix::Decimal,
600 };
601
602 // Checks that all characters after the base prefix are all valid digits for that base.
603 if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) {
604 Some(res)
605 } else {
606 None
607 }
608 }
609
610 const fn prefix_len(&self) -> usize {
611 match self {
612 Self::Decimal => 0,
613 _ => 2,
614 }
615 }
616}