X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_ast%2Fsrc%2Futil%2Fliteral.rs;h=0daeecb53a8b9d88a1432fa05440360de7096cad;hb=2cd2070af7643ad88d280a4933bc4fb60451e521;hp=f6f186b51073b788d46438e87583c6afbcb755bc;hpb=532fe7b8e043115477e33ad0d97dfe9469a2c236;p=rust.git diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index f6f186b5107..0daeecb53a8 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -1,11 +1,31 @@ //! Code related to parsing literals. -use crate::ast::{self, LitKind, MetaItemLit}; +use crate::ast::{self, LitKind, MetaItemLit, StrStyle}; use crate::token::{self, Token}; use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use std::ascii; +use std::{ascii, fmt, str}; + +// Escapes a string, represented as a symbol. Reuses the original symbol, +// avoiding interning, if no changes are required. +pub fn escape_string_symbol(symbol: Symbol) -> Symbol { + let s = symbol.as_str(); + let escaped = s.escape_default().to_string(); + if s == escaped { symbol } else { Symbol::intern(&escaped) } +} + +// Escapes a char. +pub fn escape_char_symbol(ch: char) -> Symbol { + let s: String = ch.escape_default().map(Into::::into).collect(); + Symbol::intern(&s) +} + +// Escapes a byte string. +pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol { + let s = bytes.escape_ascii().to_string(); + Symbol::intern(&s) +} #[derive(Debug)] pub enum LitError { @@ -115,9 +135,9 @@ pub fn from_token_lit(lit: token::Lit) -> Result { } }); error?; - LitKind::ByteStr(buf.into()) + LitKind::ByteStr(buf.into(), StrStyle::Cooked) } - token::ByteStrRaw(_) => { + token::ByteStrRaw(n) => { let s = symbol.as_str(); let bytes = if s.contains('\r') { let mut buf = Vec::with_capacity(s.len()); @@ -136,69 +156,95 @@ pub fn from_token_lit(lit: token::Lit) -> Result { symbol.to_string().into_bytes() }; - LitKind::ByteStr(bytes.into()) + LitKind::ByteStr(bytes.into(), StrStyle::Raw(n)) } token::Err => LitKind::Err, }) } +} - /// Attempts to recover a token from semantic literal. - /// This function is used when the original token doesn't exist (e.g. the literal is created - /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn to_token_lit(&self) -> token::Lit { - let (kind, symbol, suffix) = match *self { - LitKind::Str(symbol, ast::StrStyle::Cooked) => { - // Don't re-intern unless the escaped string is different. - let s = symbol.as_str(); - let escaped = s.escape_default().to_string(); - let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) }; - (token::Str, symbol, None) - } - LitKind::Str(symbol, ast::StrStyle::Raw(n)) => (token::StrRaw(n), symbol, None), - LitKind::ByteStr(ref bytes) => { - let string = bytes.escape_ascii().to_string(); - (token::ByteStr, Symbol::intern(&string), None) +impl fmt::Display for LitKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + LitKind::Byte(b) => { + let b: String = ascii::escape_default(b).map(Into::::into).collect(); + write!(f, "b'{}'", b)?; } - LitKind::Byte(byte) => { - let string: String = ascii::escape_default(byte).map(Into::::into).collect(); - (token::Byte, Symbol::intern(&string), None) + LitKind::Char(ch) => write!(f, "'{}'", escape_char_symbol(ch))?, + LitKind::Str(sym, StrStyle::Cooked) => write!(f, "\"{}\"", escape_string_symbol(sym))?, + LitKind::Str(sym, StrStyle::Raw(n)) => write!( + f, + "r{delim}\"{string}\"{delim}", + delim = "#".repeat(n as usize), + string = sym + )?, + LitKind::ByteStr(ref bytes, StrStyle::Cooked) => { + write!(f, "b\"{}\"", escape_byte_str_symbol(bytes))? } - LitKind::Char(ch) => { - let string: String = ch.escape_default().map(Into::::into).collect(); - (token::Char, Symbol::intern(&string), None) + LitKind::ByteStr(ref bytes, StrStyle::Raw(n)) => { + // Unwrap because raw byte string literals can only contain ASCII. + let symbol = str::from_utf8(bytes).unwrap(); + write!( + f, + "br{delim}\"{string}\"{delim}", + delim = "#".repeat(n as usize), + string = symbol + )?; } LitKind::Int(n, ty) => { - let suffix = match ty { - ast::LitIntType::Unsigned(ty) => Some(ty.name()), - ast::LitIntType::Signed(ty) => Some(ty.name()), - ast::LitIntType::Unsuffixed => None, - }; - (token::Integer, sym::integer(n), suffix) + write!(f, "{}", n)?; + match ty { + ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?, + ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?, + ast::LitIntType::Unsuffixed => {} + } } LitKind::Float(symbol, ty) => { - let suffix = match ty { - ast::LitFloatType::Suffixed(ty) => Some(ty.name()), - ast::LitFloatType::Unsuffixed => None, - }; - (token::Float, symbol, suffix) + write!(f, "{}", symbol)?; + match ty { + ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?, + ast::LitFloatType::Unsuffixed => {} + } } - LitKind::Bool(value) => { - let symbol = if value { kw::True } else { kw::False }; - (token::Bool, symbol, None) + LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?, + LitKind::Err => { + // This only shows up in places like `-Zunpretty=hir` output, so we + // don't bother to produce something useful. + write!(f, "")?; } - // This only shows up in places like `-Zunpretty=hir` output, so we - // don't bother to produce something useful. - LitKind::Err => (token::Err, Symbol::intern(""), None), - }; + } - token::Lit::new(kind, symbol, suffix) + Ok(()) } } impl MetaItemLit { - /// Converts token literal into a meta item literal. + /// Converts a token literal into a meta item literal. pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { - Ok(MetaItemLit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) + Ok(MetaItemLit { + symbol: token_lit.symbol, + suffix: token_lit.suffix, + kind: LitKind::from_token_lit(token_lit)?, + span, + }) + } + + /// Cheaply converts a meta item literal into a token literal. + pub fn as_token_lit(&self) -> token::Lit { + let kind = match self.kind { + LitKind::Bool(_) => token::Bool, + LitKind::Str(_, ast::StrStyle::Cooked) => token::Str, + LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n), + LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr, + LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n), + LitKind::Byte(_) => token::Byte, + LitKind::Char(_) => token::Char, + LitKind::Int(..) => token::Integer, + LitKind::Float(..) => token::Float, + LitKind::Err => token::Err, + }; + + token::Lit::new(kind, self.symbol, self.suffix) } /// Converts an arbitrary token into meta item literal.