From 9856144b0bdc1519c04a387ac4a9805722710c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 5 May 2022 08:10:07 +0300 Subject: [PATCH] Lower values of char and byte literals --- crates/hir-def/src/body/lower.rs | 6 +- crates/ide/src/hover/tests.rs | 88 +++++++++++++++++++++++ crates/rust-analyzer/src/lib.rs | 1 - crates/syntax/src/ast/expr_ext.rs | 12 ++-- crates/syntax/src/ast/generated/tokens.rs | 42 +++++++++++ crates/syntax/src/ast/token_ext.rs | 34 ++++++++- crates/syntax/src/tests/sourcegen_ast.rs | 2 +- crates/syntax/src/validation.rs | 4 +- 8 files changed, 178 insertions(+), 11 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index f0cb39ec36..e8303ec40f 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -983,9 +983,11 @@ impl From 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()), } } } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 95420f2ffe..74c5c98689 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -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 "#]], ); diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index d29ec512d6..3b9e201f57 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -8,7 +8,6 @@ //! //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. -#![recursion_limit = "512"] pub mod cli; diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index 1d0f393ec1..17785152bc 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs @@ -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!(), } } diff --git a/crates/syntax/src/ast/generated/tokens.rs b/crates/syntax/src/ast/generated/tokens.rs index 30f23b9d96..a3209c5abd 100644 --- a/crates/syntax/src/ast/generated/tokens.rs +++ b/crates/syntax/src/ast/generated/tokens.rs @@ -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 { + 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 { + 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, diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index f1e5c2136f..4b6dc236b5 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -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 { + 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 { + 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() + } +} diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index c2ed3eab0a..4cfb8075cb 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -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::>(), diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 286affbba9..c2c2c82e11 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs @@ -151,12 +151,12 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec) { } } } - 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); }