More orthogonal API

This commit is contained in:
Aleksey Kladov 2020-11-06 19:01:25 +01:00
parent 735aaa7b39
commit eb46033390
2 changed files with 38 additions and 48 deletions

View File

@ -1,4 +1,4 @@
use syntax::{ast, ast::Radix, AstNode};
use syntax::{ast, ast::Radix, AstToken};
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
@ -14,15 +14,13 @@
// const _: i32 = 0b1010;
// ```
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.as_int_number()?.value()?;
let literal = ctx.find_node_at_offset::<ast::Literal>()?.as_int_number()?;
let radix = literal.radix();
let value = literal.value()?;
let suffix = literal.suffix();
let range = literal.syntax().text_range();
let group_id = GroupLabel("Convert integer base".into());
let suffix = match literal.kind() {
ast::LiteralKind::IntNumber { suffix } => suffix,
_ => return None,
};
for &target_radix in Radix::ALL {
if target_radix == radix {
@ -36,16 +34,11 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext) ->
Radix::Hexadecimal => format!("0x{:X}", value),
};
let label = format!(
"Convert {} to {}{}",
literal,
converted,
suffix.as_deref().unwrap_or_default()
);
let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default());
// Appends the type suffix back into the new literal if it exists.
if let Some(suffix) = &suffix {
converted.push_str(&suffix);
if let Some(suffix) = suffix {
converted.push_str(suffix);
}
acc.add_group(

View File

@ -166,6 +166,7 @@ fn value(&self) -> Option<Cow<'_, str>> {
}
}
// FIXME: merge `ast::RawString` and `ast::String`.
impl HasStringValue for ast::RawString {
fn value(&self) -> Option<Cow<'_, str>> {
let text = self.text().as_str();
@ -544,29 +545,46 @@ impl ast::IntNumber {
"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)> {
pub fn radix(&self) -> Radix {
match self.text().get(..2).unwrap_or_default() {
"0b" => Radix::Binary,
"0o" => Radix::Octal,
"0x" => Radix::Hexadecimal,
_ => Radix::Decimal,
}
}
pub fn value(&self) -> Option<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;
}
if let Some(suffix) = self.suffix() {
text = &text[..text.len() - suffix.len()]
}
let radix = self.radix();
text = &text[radix.prefix_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))
let value = u128::from_str_radix(text, radix as u32).ok()?;
Some(value)
}
pub fn suffix(&self) -> Option<&str> {
let text = self.text();
// FIXME: don't check a fixed set of suffixes, `1_0_1___lol` is valid
// syntax, suffix is `lol`.
ast::IntNumber::SUFFIXES.iter().find_map(|suffix| {
if text.ends_with(suffix) {
return Some(&text[text.len() - suffix.len()..]);
}
None
})
}
}
@ -586,27 +604,6 @@ 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,