mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-01 07:48:45 +00:00
Auto merge of #12157 - lnicola:lower-char-byte-literals, r=Veykril
feat: Lower values of char and byte literals Closes #12137
This commit is contained in:
commit
e789d73424
8 changed files with 178 additions and 11 deletions
|
@ -983,9 +983,11 @@ impl From<ast::LiteralKind> for Literal {
|
||||||
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
|
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
|
||||||
Literal::String(text)
|
Literal::String(text)
|
||||||
}
|
}
|
||||||
LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
|
LiteralKind::Byte(b) => {
|
||||||
|
Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
|
||||||
|
}
|
||||||
|
LiteralKind::Char(c) => Literal::Char(c.value().unwrap_or_default()),
|
||||||
LiteralKind::Bool(val) => Literal::Bool(val),
|
LiteralKind::Bool(val) => Literal::Bool(val),
|
||||||
LiteralKind::Char => Literal::Char(Default::default()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3507,6 +3507,94 @@ const FOO$0: &str = "bar";
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
This is a doc
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
// show char literal
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
/// This is a doc
|
||||||
|
const FOO$0: char = 'a';
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*FOO*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const FOO: char = 'a'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a doc
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
// show escaped char literal
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
/// This is a doc
|
||||||
|
const FOO$0: char = '\x61';
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*FOO*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const FOO: char = 'a'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a doc
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
// show byte literal
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
/// This is a doc
|
||||||
|
const FOO$0: u8 = b'a';
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*FOO*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const FOO: u8 = 97 (0x61)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a doc
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
// show escaped byte literal
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
/// This is a doc
|
||||||
|
const FOO$0: u8 = b'\x61';
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*FOO*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const FOO: u8 = 97 (0x61)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
This is a doc
|
This is a doc
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
//!
|
//!
|
||||||
//! The `cli` submodule implements some batch-processing analysis, primarily as
|
//! The `cli` submodule implements some batch-processing analysis, primarily as
|
||||||
//! a debugging aid.
|
//! a debugging aid.
|
||||||
#![recursion_limit = "512"]
|
|
||||||
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
|
||||||
|
|
|
@ -283,8 +283,8 @@ pub enum LiteralKind {
|
||||||
ByteString(ast::ByteString),
|
ByteString(ast::ByteString),
|
||||||
IntNumber(ast::IntNumber),
|
IntNumber(ast::IntNumber),
|
||||||
FloatNumber(ast::FloatNumber),
|
FloatNumber(ast::FloatNumber),
|
||||||
Char,
|
Char(ast::Char),
|
||||||
Byte,
|
Byte(ast::Byte),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,12 +312,16 @@ impl ast::Literal {
|
||||||
if let Some(t) = ast::ByteString::cast(token.clone()) {
|
if let Some(t) = ast::ByteString::cast(token.clone()) {
|
||||||
return LiteralKind::ByteString(t);
|
return LiteralKind::ByteString(t);
|
||||||
}
|
}
|
||||||
|
if let Some(t) = ast::Char::cast(token.clone()) {
|
||||||
|
return LiteralKind::Char(t);
|
||||||
|
}
|
||||||
|
if let Some(t) = ast::Byte::cast(token.clone()) {
|
||||||
|
return LiteralKind::Byte(t);
|
||||||
|
}
|
||||||
|
|
||||||
match token.kind() {
|
match token.kind() {
|
||||||
T![true] => LiteralKind::Bool(true),
|
T![true] => LiteralKind::Bool(true),
|
||||||
T![false] => LiteralKind::Bool(false),
|
T![false] => LiteralKind::Bool(false),
|
||||||
CHAR => LiteralKind::Char,
|
|
||||||
BYTE => LiteralKind::Byte,
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,48 @@ impl AstToken for FloatNumber {
|
||||||
fn syntax(&self) -> &SyntaxToken { &self.syntax }
|
fn syntax(&self) -> &SyntaxToken { &self.syntax }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Char {
|
||||||
|
pub(crate) syntax: SyntaxToken,
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Char {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.syntax, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AstToken for Char {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == CHAR }
|
||||||
|
fn cast(syntax: SyntaxToken) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxToken { &self.syntax }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Byte {
|
||||||
|
pub(crate) syntax: SyntaxToken,
|
||||||
|
}
|
||||||
|
impl std::fmt::Display for Byte {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.syntax, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AstToken for Byte {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == BYTE }
|
||||||
|
fn cast(syntax: SyntaxToken) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxToken { &self.syntax }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
pub(crate) syntax: SyntaxToken,
|
pub(crate) syntax: SyntaxToken,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use rustc_lexer::unescape::{unescape_literal, Mode};
|
use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, AstToken},
|
ast::{self, AstToken},
|
||||||
|
@ -406,3 +406,35 @@ mod tests {
|
||||||
check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
|
check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ast::Char {
|
||||||
|
pub fn value(&self) -> Option<char> {
|
||||||
|
let mut text = self.text();
|
||||||
|
if text.starts_with('\'') {
|
||||||
|
text = &text[1..];
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if text.ends_with('\'') {
|
||||||
|
text = &text[0..text.len() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
unescape_char(text).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ast::Byte {
|
||||||
|
pub fn value(&self) -> Option<u8> {
|
||||||
|
let mut text = self.text();
|
||||||
|
if text.starts_with("b\'") {
|
||||||
|
text = &text[2..];
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if text.ends_with('\'') {
|
||||||
|
text = &text[0..text.len() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
unescape_byte(text).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -585,7 +585,7 @@ impl Field {
|
||||||
|
|
||||||
fn lower(grammar: &Grammar) -> AstSrc {
|
fn lower(grammar: &Grammar) -> AstSrc {
|
||||||
let mut res = AstSrc {
|
let mut res = AstSrc {
|
||||||
tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Ident"
|
tokens: "Whitespace Comment String ByteString IntNumber FloatNumber Char Byte Ident"
|
||||||
.split_ascii_whitespace()
|
.split_ascii_whitespace()
|
||||||
.map(|it| it.to_string())
|
.map(|it| it.to_string())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
|
|
|
@ -151,12 +151,12 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::LiteralKind::Char => {
|
ast::LiteralKind::Char(_) => {
|
||||||
if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
|
if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
|
||||||
push_err(1, e);
|
push_err(1, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::LiteralKind::Byte => {
|
ast::LiteralKind::Byte(_) => {
|
||||||
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
|
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
|
||||||
push_err(2, e);
|
push_err(2, e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue