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:
bors 2022-05-05 07:35:41 +00:00
commit e789d73424
8 changed files with 178 additions and 11 deletions

View file

@ -983,9 +983,11 @@ impl From<ast::LiteralKind> for Literal {
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
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::Char => Literal::Char(Default::default()),
}
}
}

View file

@ -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
"#]],
);

View file

@ -8,7 +8,6 @@
//!
//! The `cli` submodule implements some batch-processing analysis, primarily as
//! a debugging aid.
#![recursion_limit = "512"]
pub mod cli;

View file

@ -283,8 +283,8 @@ pub enum LiteralKind {
ByteString(ast::ByteString),
IntNumber(ast::IntNumber),
FloatNumber(ast::FloatNumber),
Char,
Byte,
Char(ast::Char),
Byte(ast::Byte),
Bool(bool),
}
@ -312,12 +312,16 @@ impl ast::Literal {
if let Some(t) = ast::ByteString::cast(token.clone()) {
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() {
T![true] => LiteralKind::Bool(true),
T![false] => LiteralKind::Bool(false),
CHAR => LiteralKind::Char,
BYTE => LiteralKind::Byte,
_ => unreachable!(),
}
}

View file

@ -132,6 +132,48 @@ impl AstToken for FloatNumber {
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)]
pub struct Ident {
pub(crate) syntax: SyntaxToken,

View file

@ -2,7 +2,7 @@
use std::borrow::Cow;
use rustc_lexer::unescape::{unescape_literal, Mode};
use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
use crate::{
ast::{self, AstToken},
@ -406,3 +406,35 @@ mod tests {
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()
}
}

View file

@ -585,7 +585,7 @@ impl Field {
fn lower(grammar: &Grammar) -> 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()
.map(|it| it.to_string())
.collect::<Vec<_>>(),

View file

@ -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) {
push_err(1, e);
}
}
ast::LiteralKind::Byte => {
ast::LiteralKind::Byte(_) => {
if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
push_err(2, e);
}