mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 08:36:03 +00:00
Move int parsing to IntNumber token
This commit is contained in:
parent
6bcc33e5b7
commit
735aaa7b39
@ -15,7 +15,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
|
||||
// ```
|
||||
pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let literal = ctx.find_node_at_offset::<ast::Literal>()?;
|
||||
let (radix, value) = literal.int_value()?;
|
||||
let (radix, value) = literal.as_int_number()?.value()?;
|
||||
|
||||
let range = literal.syntax().text_range();
|
||||
let group_id = GroupLabel("Convert integer base".into());
|
||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, Radix, RangeOp},
|
||||
expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp},
|
||||
generated::{nodes::*, tokens::*},
|
||||
node_ext::{
|
||||
AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
ast::{self, support, AstChildren, AstNode},
|
||||
SmolStr,
|
||||
AstToken, SmolStr,
|
||||
SyntaxKind::*,
|
||||
SyntaxToken, T,
|
||||
};
|
||||
@ -316,6 +316,10 @@ impl ast::Literal {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn as_int_number(&self) -> Option<ast::IntNumber> {
|
||||
ast::IntNumber::cast(self.token())
|
||||
}
|
||||
|
||||
fn find_suffix(text: &str, possible_suffixes: &[&str]) -> Option<SmolStr> {
|
||||
possible_suffixes
|
||||
.iter()
|
||||
@ -324,11 +328,6 @@ impl ast::Literal {
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> LiteralKind {
|
||||
const INT_SUFFIXES: [&str; 12] = [
|
||||
"u64", "u32", "u16", "u8", "usize", "isize", "i64", "i32", "i16", "i8", "u128", "i128",
|
||||
];
|
||||
const FLOAT_SUFFIXES: [&str; 2] = ["f32", "f64"];
|
||||
|
||||
let token = self.token();
|
||||
|
||||
match token.kind() {
|
||||
@ -337,17 +336,20 @@ impl ast::Literal {
|
||||
// The lexer treats e.g. `1f64` as an integer literal. See
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/1592
|
||||
// and the comments on the linked PR.
|
||||
|
||||
let text = token.text();
|
||||
if let suffix @ Some(_) = Self::find_suffix(&text, &FLOAT_SUFFIXES) {
|
||||
if let suffix @ Some(_) = Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES) {
|
||||
LiteralKind::FloatNumber { suffix }
|
||||
} else {
|
||||
LiteralKind::IntNumber { suffix: Self::find_suffix(&text, &INT_SUFFIXES) }
|
||||
LiteralKind::IntNumber {
|
||||
suffix: Self::find_suffix(&text, &ast::IntNumber::SUFFIXES),
|
||||
}
|
||||
}
|
||||
}
|
||||
FLOAT_NUMBER => {
|
||||
let text = token.text();
|
||||
LiteralKind::FloatNumber { suffix: Self::find_suffix(&text, &FLOAT_SUFFIXES) }
|
||||
LiteralKind::FloatNumber {
|
||||
suffix: Self::find_suffix(&text, &ast::FloatNumber::SUFFIXES),
|
||||
}
|
||||
}
|
||||
STRING | RAW_STRING => LiteralKind::String,
|
||||
T![true] => LiteralKind::Bool(true),
|
||||
@ -358,71 +360,6 @@ impl ast::Literal {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: should probably introduce string token type?
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/6308
|
||||
pub fn int_value(&self) -> Option<(Radix, u128)> {
|
||||
let suffix = match self.kind() {
|
||||
LiteralKind::IntNumber { suffix } => suffix,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let token = self.token();
|
||||
let mut text = token.text().as_str();
|
||||
text = &text[..text.len() - suffix.map_or(0, |it| it.len())];
|
||||
|
||||
let buf;
|
||||
if text.contains("_") {
|
||||
buf = text.replace('_', "");
|
||||
text = buf.as_str();
|
||||
};
|
||||
|
||||
let radix = Radix::identify(text)?;
|
||||
let digits = &text[radix.prefix_len()..];
|
||||
let value = u128::from_str_radix(digits, radix as u32).ok()?;
|
||||
Some((radix, value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum Radix {
|
||||
Binary = 2,
|
||||
Octal = 8,
|
||||
Decimal = 10,
|
||||
Hexadecimal = 16,
|
||||
}
|
||||
|
||||
impl Radix {
|
||||
pub const ALL: &'static [Radix] =
|
||||
&[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
|
||||
|
||||
fn identify(literal_text: &str) -> Option<Self> {
|
||||
// We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible.
|
||||
if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) {
|
||||
return Some(Self::Decimal);
|
||||
}
|
||||
|
||||
let res = match &literal_text[..2] {
|
||||
"0b" => Radix::Binary,
|
||||
"0o" => Radix::Octal,
|
||||
"0x" => Radix::Hexadecimal,
|
||||
_ => Radix::Decimal,
|
||||
};
|
||||
|
||||
// Checks that all characters after the base prefix are all valid digits for that base.
|
||||
if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) {
|
||||
Some(res)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn prefix_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Decimal => 0,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -536,3 +536,81 @@ impl HasFormatSpecifier for ast::RawString {
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::IntNumber {
|
||||
#[rustfmt::skip]
|
||||
pub(crate) const SUFFIXES: &'static [&'static str] = &[
|
||||
"u8", "u16", "u32", "u64", "u128", "usize",
|
||||
"i8", "i16", "i32", "i64", "i128", "isize",
|
||||
];
|
||||
|
||||
// FIXME: should probably introduce string token type?
|
||||
// https://github.com/rust-analyzer/rust-analyzer/issues/6308
|
||||
pub fn value(&self) -> Option<(Radix, u128)> {
|
||||
let token = self.syntax();
|
||||
|
||||
let mut text = token.text().as_str();
|
||||
for suffix in ast::IntNumber::SUFFIXES {
|
||||
if let Some(without_suffix) = text.strip_suffix(suffix) {
|
||||
text = without_suffix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let buf;
|
||||
if text.contains("_") {
|
||||
buf = text.replace('_', "");
|
||||
text = buf.as_str();
|
||||
};
|
||||
|
||||
let radix = Radix::identify(text)?;
|
||||
let digits = &text[radix.prefix_len()..];
|
||||
let value = u128::from_str_radix(digits, radix as u32).ok()?;
|
||||
Some((radix, value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::FloatNumber {
|
||||
pub(crate) const SUFFIXES: &'static [&'static str] = &["f32", "f64"];
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum Radix {
|
||||
Binary = 2,
|
||||
Octal = 8,
|
||||
Decimal = 10,
|
||||
Hexadecimal = 16,
|
||||
}
|
||||
|
||||
impl Radix {
|
||||
pub const ALL: &'static [Radix] =
|
||||
&[Radix::Binary, Radix::Octal, Radix::Decimal, Radix::Hexadecimal];
|
||||
|
||||
fn identify(literal_text: &str) -> Option<Self> {
|
||||
// We cannot express a literal in anything other than decimal in under 3 characters, so we return here if possible.
|
||||
if literal_text.len() < 3 && literal_text.chars().all(|c| c.is_digit(10)) {
|
||||
return Some(Self::Decimal);
|
||||
}
|
||||
|
||||
let res = match &literal_text[..2] {
|
||||
"0b" => Radix::Binary,
|
||||
"0o" => Radix::Octal,
|
||||
"0x" => Radix::Hexadecimal,
|
||||
_ => Radix::Decimal,
|
||||
};
|
||||
|
||||
// Checks that all characters after the base prefix are all valid digits for that base.
|
||||
if literal_text[res.prefix_len()..].chars().all(|c| c.is_digit(res as u32)) {
|
||||
Some(res)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn prefix_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Decimal => 0,
|
||||
_ => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user