1use std::fmt::Write as _;
4use std::{ascii, fmt, str};
5
6use rustc_literal_escaper::{
7 MixedUnit, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str,
8};
9use rustc_span::{ByteSymbol, Span, Symbol, kw, sym};
10use tracing::debug;
11
12use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
13use crate::token::{self, Token};
14
15pub fn escape_string_symbol(symbol: Symbol) -> Symbol {
18 let s = symbol.as_str();
19
20 fn requires_escape(b: &u8) -> bool {
21 match *b {
22 b'\\' | b'\'' | b'"' => true,
23 b'\x20'..=b'\x7e' => false,
24 _ => true,
25 }
26 }
27
28 let Some(position) = s.as_bytes().iter().position(requires_escape) else {
30 return symbol;
31 };
32
33 let (prefix, suffix) = s.split_at(position);
35
36 let mut escaped = String::with_capacity(s.len() + 1);
39 escaped.push_str(prefix);
40
41 for c in suffix.chars() {
43 match c {
44 '\t' => escaped.push_str("\\t"),
45 '\r' => escaped.push_str("\\r"),
46 '\n' => escaped.push_str("\\n"),
47 '\\' => escaped.push_str("\\\\"),
48 '\'' => escaped.push_str("\\'"),
49 '\"' => escaped.push_str("\\\""),
50 '\x20'..='\x7e' => escaped.push(c),
51 c => escaped.write_fmt(format_args!("\\u{{{0:x}}}", c as u32))write!(escaped, "\\u{{{:x}}}", c as u32).unwrap(),
52 }
53 }
54 Symbol::intern(&escaped)
55}
56
57pub fn escape_char_symbol(ch: char) -> Symbol {
59 let s: String = ch.escape_default().map(Into::<char>::into).collect();
60 Symbol::intern(&s)
61}
62
63pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol {
65 let s = bytes.escape_ascii().to_string();
66 Symbol::intern(&s)
67}
68
69#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LitError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
LitError::InvalidSuffix(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidSuffix", &__self_0),
LitError::InvalidIntSuffix(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidIntSuffix", &__self_0),
LitError::InvalidFloatSuffix(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"InvalidFloatSuffix", &__self_0),
LitError::NonDecimalFloat(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"NonDecimalFloat", &__self_0),
LitError::IntTooLarge(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"IntTooLarge", &__self_0),
}
}
}Debug)]
70pub enum LitError {
71 InvalidSuffix(Symbol),
72 InvalidIntSuffix(Symbol),
73 InvalidFloatSuffix(Symbol),
74 NonDecimalFloat(u32), IntTooLarge(u32), }
77
78impl LitKind {
79 pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> {
81 let token::Lit { kind, symbol, suffix } = lit;
82 if let Some(suffix) = suffix
83 && !kind.may_have_suffix()
84 {
85 return Err(LitError::InvalidSuffix(suffix));
86 }
87
88 Ok(match kind {
92 token::Bool => {
93 if !symbol.is_bool_lit() {
::core::panicking::panic("assertion failed: symbol.is_bool_lit()")
};assert!(symbol.is_bool_lit());
94 LitKind::Bool(symbol == kw::True)
95 }
96 token::Byte => {
97 return unescape_byte(symbol.as_str())
98 .map(LitKind::Byte)
99 .map_err(|_| {
::core::panicking::panic_fmt(format_args!("failed to unescape byte literal"));
}panic!("failed to unescape byte literal"));
100 }
101 token::Char => {
102 return unescape_char(symbol.as_str())
103 .map(LitKind::Char)
104 .map_err(|_| {
::core::panicking::panic_fmt(format_args!("failed to unescape char literal"));
}panic!("failed to unescape char literal"));
105 }
106
107 token::Integer => return integer_lit(symbol, suffix),
110 token::Float => return float_lit(symbol, suffix),
111
112 token::Str => {
113 let s = symbol.as_str();
118 let symbol = if s.contains('\\') {
121 let mut buf = String::with_capacity(s.len());
122 unescape_str(
126 s,
127 #[inline(always)]
128 |_, res| match res {
129 Ok(c) => buf.push(c),
130 Err(err) => {
131 if !!err.is_fatal() {
{
::core::panicking::panic_fmt(format_args!("failed to unescape string literal"));
}
}assert!(!err.is_fatal(), "failed to unescape string literal")
132 }
133 },
134 );
135 Symbol::intern(&buf)
136 } else {
137 symbol
138 };
139 LitKind::Str(symbol, ast::StrStyle::Cooked)
140 }
141 token::StrRaw(n) => {
142 LitKind::Str(symbol, ast::StrStyle::Raw(n))
144 }
145 token::ByteStr => {
146 let s = symbol.as_str();
147 let mut buf = Vec::with_capacity(s.len());
148 unescape_byte_str(s, |_, res| match res {
149 Ok(b) => buf.push(b),
150 Err(err) => {
151 if !!err.is_fatal() {
{
::core::panicking::panic_fmt(format_args!("failed to unescape string literal"));
}
}assert!(!err.is_fatal(), "failed to unescape string literal")
152 }
153 });
154 LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Cooked)
155 }
156 token::ByteStrRaw(n) => {
157 let buf = symbol.as_str().to_owned().into_bytes();
159 LitKind::ByteStr(ByteSymbol::intern(&buf), StrStyle::Raw(n))
160 }
161 token::CStr => {
162 let s = symbol.as_str();
163 let mut buf = Vec::with_capacity(s.len());
164 unescape_c_str(s, |_span, res| match res {
165 Ok(MixedUnit::Char(c)) => {
166 buf.extend_from_slice(c.get().encode_utf8(&mut [0; 4]).as_bytes())
167 }
168 Ok(MixedUnit::HighByte(b)) => buf.push(b.get()),
169 Err(err) => {
170 if !!err.is_fatal() {
{
::core::panicking::panic_fmt(format_args!("failed to unescape C string literal"));
}
}assert!(!err.is_fatal(), "failed to unescape C string literal")
171 }
172 });
173 buf.push(0);
174 LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Cooked)
175 }
176 token::CStrRaw(n) => {
177 let mut buf = symbol.as_str().to_owned().into_bytes();
181 buf.push(0);
182 LitKind::CStr(ByteSymbol::intern(&buf), StrStyle::Raw(n))
183 }
184 token::Err(guar) => LitKind::Err(guar),
185 })
186 }
187}
188
189impl fmt::Display for LitKind {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 match *self {
192 LitKind::Byte(b) => {
193 let b: String = ascii::escape_default(b).map(Into::<char>::into).collect();
194 f.write_fmt(format_args!("b\'{0}\'", b))write!(f, "b'{b}'")?;
195 }
196 LitKind::Char(ch) => f.write_fmt(format_args!("\'{0}\'", escape_char_symbol(ch)))write!(f, "'{}'", escape_char_symbol(ch))?,
197 LitKind::Str(sym, StrStyle::Cooked) => f.write_fmt(format_args!("\"{0}\"", escape_string_symbol(sym)))write!(f, "\"{}\"", escape_string_symbol(sym))?,
198 LitKind::Str(sym, StrStyle::Raw(n)) => f.write_fmt(format_args!("r{0}\"{1}\"{0}", "#".repeat(n as usize), sym))write!(
199 f,
200 "r{delim}\"{string}\"{delim}",
201 delim = "#".repeat(n as usize),
202 string = sym
203 )?,
204 LitKind::ByteStr(ref byte_sym, StrStyle::Cooked) => {
205 f.write_fmt(format_args!("b\"{0}\"",
escape_byte_str_symbol(byte_sym.as_byte_str())))write!(f, "b\"{}\"", escape_byte_str_symbol(byte_sym.as_byte_str()))?
206 }
207 LitKind::ByteStr(ref byte_sym, StrStyle::Raw(n)) => {
208 let symbol = str::from_utf8(byte_sym.as_byte_str()).unwrap();
210 f.write_fmt(format_args!("br{0}\"{1}\"{0}", "#".repeat(n as usize), symbol))write!(
211 f,
212 "br{delim}\"{string}\"{delim}",
213 delim = "#".repeat(n as usize),
214 string = symbol
215 )?;
216 }
217 LitKind::CStr(ref bytes, StrStyle::Cooked) => {
218 f.write_fmt(format_args!("c\"{0}\"",
escape_byte_str_symbol(bytes.as_byte_str())))write!(f, "c\"{}\"", escape_byte_str_symbol(bytes.as_byte_str()))?
219 }
220 LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
221 let symbol = str::from_utf8(bytes.as_byte_str()).unwrap();
223 f.write_fmt(format_args!("cr{0}\"{1}\"{0}", "#".repeat(n as usize), symbol))write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
224 }
225 LitKind::Int(n, ty) => {
226 f.write_fmt(format_args!("{0}", n))write!(f, "{n}")?;
227 match ty {
228 ast::LitIntType::Unsigned(ty) => f.write_fmt(format_args!("{0}", ty.name_str()))write!(f, "{}", ty.name_str())?,
229 ast::LitIntType::Signed(ty) => f.write_fmt(format_args!("{0}", ty.name_str()))write!(f, "{}", ty.name_str())?,
230 ast::LitIntType::Unsuffixed => {}
231 }
232 }
233 LitKind::Float(symbol, ty) => {
234 f.write_fmt(format_args!("{0}", symbol))write!(f, "{symbol}")?;
235 match ty {
236 ast::LitFloatType::Suffixed(ty) => f.write_fmt(format_args!("{0}", ty.name_str()))write!(f, "{}", ty.name_str())?,
237 ast::LitFloatType::Unsuffixed => {}
238 }
239 }
240 LitKind::Bool(b) => f.write_fmt(format_args!("{0}", if b { "true" } else { "false" }))write!(f, "{}", if b { "true" } else { "false" })?,
241 LitKind::Err(_) => {
242 f.write_fmt(format_args!("<bad-literal>"))write!(f, "<bad-literal>")?;
245 }
246 }
247
248 Ok(())
249 }
250}
251
252impl MetaItemLit {
253 pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result<MetaItemLit, LitError> {
255 Ok(MetaItemLit {
256 symbol: token_lit.symbol,
257 suffix: token_lit.suffix,
258 kind: LitKind::from_token_lit(token_lit)?,
259 span,
260 })
261 }
262
263 pub fn as_token_lit(&self) -> token::Lit {
265 let kind = match self.kind {
266 LitKind::Bool(_) => token::Bool,
267 LitKind::Str(_, ast::StrStyle::Cooked) => token::Str,
268 LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
269 LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
270 LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
271 LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
272 LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
273 LitKind::Byte(_) => token::Byte,
274 LitKind::Char(_) => token::Char,
275 LitKind::Int(..) => token::Integer,
276 LitKind::Float(..) => token::Float,
277 LitKind::Err(guar) => token::Err(guar),
278 };
279
280 token::Lit::new(kind, self.symbol, self.suffix)
281 }
282
283 pub fn from_token(token: &Token) -> Option<MetaItemLit> {
285 token::Lit::from_token(token)
286 .and_then(|token_lit| MetaItemLit::from_token_lit(token_lit, token.span).ok())
287 }
288}
289
290fn strip_underscores(symbol: Symbol) -> Symbol {
291 let s = symbol.as_str();
293 if s.contains('_') {
294 let mut s = s.to_string();
295 s.retain(|c| c != '_');
296 return Symbol::intern(&s);
297 }
298 symbol
299}
300
301fn filtered_float_lit(
302 symbol: Symbol,
303 suffix: Option<Symbol>,
304 base: u32,
305) -> Result<LitKind, LitError> {
306 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_ast/src/util/literal.rs:306",
"rustc_ast::util::literal", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_ast/src/util/literal.rs"),
::tracing_core::__macro_support::Option::Some(306u32),
::tracing_core::__macro_support::Option::Some("rustc_ast::util::literal"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("filtered_float_lit: {0:?}, {1:?}, {2:?}",
symbol, suffix, base) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base);
307 if base != 10 {
308 return Err(LitError::NonDecimalFloat(base));
309 }
310 Ok(match suffix {
311 Some(suffix) => LitKind::Float(
312 symbol,
313 ast::LitFloatType::Suffixed(match suffix {
314 sym::f16 => ast::FloatTy::F16,
315 sym::f32 => ast::FloatTy::F32,
316 sym::f64 => ast::FloatTy::F64,
317 sym::f128 => ast::FloatTy::F128,
318 _ => return Err(LitError::InvalidFloatSuffix(suffix)),
319 }),
320 ),
321 None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed),
322 })
323}
324
325fn float_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
326 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_ast/src/util/literal.rs:326",
"rustc_ast::util::literal", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_ast/src/util/literal.rs"),
::tracing_core::__macro_support::Option::Some(326u32),
::tracing_core::__macro_support::Option::Some("rustc_ast::util::literal"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("float_lit: {0:?}, {1:?}",
symbol, suffix) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("float_lit: {:?}, {:?}", symbol, suffix);
327 filtered_float_lit(strip_underscores(symbol), suffix, 10)
328}
329
330fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitError> {
331 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_ast/src/util/literal.rs:331",
"rustc_ast::util::literal", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_ast/src/util/literal.rs"),
::tracing_core::__macro_support::Option::Some(331u32),
::tracing_core::__macro_support::Option::Some("rustc_ast::util::literal"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("integer_lit: {0:?}, {1:?}",
symbol, suffix) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("integer_lit: {:?}, {:?}", symbol, suffix);
332 let symbol = strip_underscores(symbol);
333 let s = symbol.as_str();
334
335 let base = match s.as_bytes() {
336 [b'0', b'x', ..] => 16,
337 [b'0', b'o', ..] => 8,
338 [b'0', b'b', ..] => 2,
339 _ => 10,
340 };
341
342 let ty = match suffix {
343 Some(suf) => match suf {
344 sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize),
345 sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8),
346 sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16),
347 sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32),
348 sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64),
349 sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128),
350 sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize),
351 sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8),
352 sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16),
353 sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32),
354 sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64),
355 sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128),
356 _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base),
359 _ => return Err(LitError::InvalidIntSuffix(suf)),
360 },
361 _ => ast::LitIntType::Unsuffixed,
362 };
363
364 let s = &s[if base != 10 { 2 } else { 0 }..];
365 u128::from_str_radix(s, base)
366 .map(|i| LitKind::Int(i.into(), ty))
367 .map_err(|_| LitError::IntTooLarge(base))
368}