Skip to content

Commit ef26263

Browse files
authored
Merge pull request #56 from eddyb/const-value-prereqs
Prerequisites for "v0: demangle structural constants and &str" (#55).
2 parents 8a39eeb + 6b3c459 commit ef26263

File tree

1 file changed

+141
-117
lines changed

1 file changed

+141
-117
lines changed

src/v0.rs

+141-117
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use core::{char, fmt, mem};
1+
use core::convert::TryFrom;
2+
use core::{char, fmt, iter, mem};
23

34
#[allow(unused_macros)]
45
macro_rules! write {
@@ -264,6 +265,30 @@ impl<'s> fmt::Display for Ident<'s> {
264265
}
265266
}
266267

268+
/// Sequence of lowercase hexadecimal nibbles (`0-9a-f`), used by leaf consts.
269+
struct HexNibbles<'s> {
270+
nibbles: &'s str,
271+
}
272+
273+
impl<'s> HexNibbles<'s> {
274+
/// Decode an integer value (with the "most significant nibble" first),
275+
/// returning `None` if it can't fit in an `u64`.
276+
// FIXME(eddyb) should this "just" use `u128` instead?
277+
fn try_parse_uint(&self) -> Option<u64> {
278+
let nibbles = self.nibbles.trim_start_matches("0");
279+
280+
if nibbles.len() > 16 {
281+
return None;
282+
}
283+
284+
let mut v = 0;
285+
for nibble in nibbles.chars() {
286+
v = (v << 4) | (nibble.to_digit(16).unwrap() as u64);
287+
}
288+
Some(v)
289+
}
290+
}
291+
267292
fn basic_type(tag: u8) -> Option<&'static str> {
268293
Some(match tag {
269294
b'b' => "bool",
@@ -331,7 +356,7 @@ impl<'s> Parser<'s> {
331356
Ok(b)
332357
}
333358

334-
fn hex_nibbles(&mut self) -> Result<&'s str, ParseError> {
359+
fn hex_nibbles(&mut self) -> Result<HexNibbles<'s>, ParseError> {
335360
let start = self.next;
336361
loop {
337362
match self.next()? {
@@ -340,7 +365,9 @@ impl<'s> Parser<'s> {
340365
_ => return Err(ParseError::Invalid),
341366
}
342367
}
343-
Ok(&self.sym[start..self.next - 1])
368+
Ok(HexNibbles {
369+
nibbles: &self.sym[start..self.next - 1],
370+
})
344371
}
345372

346373
fn digit_10(&mut self) -> Result<u8, ParseError> {
@@ -577,6 +604,35 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
577604
Ok(())
578605
}
579606

607+
/// Output the given `char`s (escaped using `char::escape_debug`), with the
608+
/// whole sequence wrapped in quotes, for either a `char` or `&str` literal,
609+
/// if printing isn't being skipped.
610+
fn print_quoted_escaped_chars(
611+
&mut self,
612+
quote: char,
613+
chars: impl Iterator<Item = char>,
614+
) -> fmt::Result {
615+
if let Some(out) = &mut self.out {
616+
use core::fmt::Write;
617+
618+
out.write_char(quote)?;
619+
for c in chars {
620+
// Special-case not escaping a single/double quote, when
621+
// inside the opposite kind of quote.
622+
if matches!((quote, c), ('\'', '"') | ('"', '\'')) {
623+
out.write_char(c)?;
624+
continue;
625+
}
626+
627+
for escaped in c.escape_debug() {
628+
out.write_char(escaped)?;
629+
}
630+
}
631+
out.write_char(quote)?;
632+
}
633+
Ok(())
634+
}
635+
580636
/// Print the lifetime according to the previously decoded index.
581637
/// An index of `0` always refers to `'_`, but starting with `1`,
582638
/// indices refer to late-bound lifetimes introduced by a binder.
@@ -946,102 +1002,68 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
9461002
}
9471003

9481004
fn print_const(&mut self) -> fmt::Result {
949-
parse!(self, push_depth);
950-
951-
if self.eat(b'B') {
952-
self.print_backref(Self::print_const)?;
953-
954-
self.pop_depth();
955-
return Ok(());
956-
}
1005+
let tag = parse!(self, next);
9571006

958-
let ty_tag = parse!(self, next);
1007+
parse!(self, push_depth);
9591008

960-
if ty_tag == b'p' {
961-
// We don't encode the type if the value is a placeholder.
962-
self.print("_")?;
1009+
match tag {
1010+
b'p' => self.print("_")?,
9631011

964-
self.pop_depth();
965-
return Ok(());
966-
}
1012+
// Primitive leaves with hex-encoded values (see `basic_type`).
1013+
b'h' | b't' | b'm' | b'y' | b'o' | b'j' => self.print_const_uint(tag)?,
1014+
b'a' | b's' | b'l' | b'x' | b'n' | b'i' => {
1015+
if self.eat(b'n') {
1016+
self.print("-")?;
1017+
}
9671018

968-
match ty_tag {
969-
// Unsigned integer types.
970-
b'h' | b't' | b'm' | b'y' | b'o' | b'j' => self.print_const_uint()?,
971-
// Signed integer types.
972-
b'a' | b's' | b'l' | b'x' | b'n' | b'i' => self.print_const_int()?,
973-
// Bool.
974-
b'b' => self.print_const_bool()?,
975-
// Char.
976-
b'c' => self.print_const_char()?,
977-
978-
// This branch ought to be unreachable.
979-
_ => invalid!(self),
980-
};
1019+
self.print_const_uint(tag)?;
1020+
}
1021+
b'b' => match parse!(self, hex_nibbles).try_parse_uint() {
1022+
Some(0) => self.print("false")?,
1023+
Some(1) => self.print("true")?,
1024+
_ => invalid!(self),
1025+
},
1026+
b'c' => {
1027+
let valid_char = parse!(self, hex_nibbles)
1028+
.try_parse_uint()
1029+
.and_then(|v| u32::try_from(v).ok())
1030+
.and_then(char::from_u32);
1031+
match valid_char {
1032+
Some(c) => self.print_quoted_escaped_chars('\'', iter::once(c))?,
1033+
None => invalid!(self),
1034+
}
1035+
}
9811036

982-
if let Some(out) = &mut self.out {
983-
if !out.alternate() {
984-
self.print(": ")?;
985-
let ty = basic_type(ty_tag).unwrap();
986-
self.print(ty)?;
1037+
b'B' => {
1038+
self.print_backref(Self::print_const)?;
9871039
}
1040+
_ => invalid!(self),
9881041
}
9891042

9901043
self.pop_depth();
9911044
Ok(())
9921045
}
9931046

994-
fn print_const_uint(&mut self) -> fmt::Result {
1047+
fn print_const_uint(&mut self, ty_tag: u8) -> fmt::Result {
9951048
let hex = parse!(self, hex_nibbles);
9961049

997-
// Print anything that doesn't fit in `u64` verbatim.
998-
if hex.len() > 16 {
999-
self.print("0x")?;
1000-
return self.print(hex);
1001-
}
1002-
1003-
let mut v = 0;
1004-
for c in hex.chars() {
1005-
v = (v << 4) | (c.to_digit(16).unwrap() as u64);
1006-
}
1007-
self.print(v)
1008-
}
1009-
1010-
fn print_const_int(&mut self) -> fmt::Result {
1011-
if self.eat(b'n') {
1012-
self.print("-")?;
1013-
}
1014-
1015-
self.print_const_uint()
1016-
}
1050+
match hex.try_parse_uint() {
1051+
Some(v) => self.print(v)?,
10171052

1018-
fn print_const_bool(&mut self) -> fmt::Result {
1019-
match parse!(self, hex_nibbles).as_bytes() {
1020-
b"0" => self.print("false"),
1021-
b"1" => self.print("true"),
1022-
_ => invalid!(self),
1023-
}
1024-
}
1025-
1026-
fn print_const_char(&mut self) -> fmt::Result {
1027-
let hex = parse!(self, hex_nibbles);
1028-
1029-
// Valid `char`s fit in `u32`.
1030-
if hex.len() > 8 {
1031-
invalid!(self);
1053+
// Print anything that doesn't fit in `u64` verbatim.
1054+
None => {
1055+
self.print("0x")?;
1056+
self.print(hex.nibbles)?;
1057+
}
10321058
}
10331059

1034-
let mut v = 0;
1035-
for c in hex.chars() {
1036-
v = (v << 4) | (c.to_digit(16).unwrap() as u32);
1037-
}
1038-
if let Some(c) = char::from_u32(v) {
1039-
if let Some(out) = &mut self.out {
1040-
fmt::Debug::fmt(&c, out)?;
1060+
if let Some(out) = &mut self.out {
1061+
if !out.alternate() {
1062+
let ty = basic_type(ty_tag).unwrap();
1063+
self.print(ty)?;
10411064
}
1042-
} else {
1043-
invalid!(self);
10441065
}
1066+
10451067
Ok(())
10461068
}
10471069
}
@@ -1050,6 +1072,11 @@ impl<'a, 'b, 's> Printer<'a, 'b, 's> {
10501072
mod tests {
10511073
use std::prelude::v1::*;
10521074

1075+
macro_rules! t {
1076+
($a:expr, $b:expr) => {{
1077+
assert_eq!(format!("{}", ::demangle($a)), $b);
1078+
}};
1079+
}
10531080
macro_rules! t_nohash {
10541081
($a:expr, $b:expr) => {{
10551082
assert_eq!(format!("{:#}", ::demangle($a)), $b);
@@ -1060,6 +1087,23 @@ mod tests {
10601087
t_nohash!(concat!("_RMC0", $a), concat!("<", $b, ">"))
10611088
};
10621089
}
1090+
macro_rules! t_const {
1091+
($mangled:expr, $value:expr) => {
1092+
t_nohash!(
1093+
concat!("_RIC0K", $mangled, "E"),
1094+
concat!("::<", $value, ">")
1095+
)
1096+
};
1097+
}
1098+
macro_rules! t_const_suffixed {
1099+
($mangled:expr, $value:expr, $value_ty_suffix:expr) => {{
1100+
t_const!($mangled, $value);
1101+
t!(
1102+
concat!("_RIC0K", $mangled, "E"),
1103+
concat!("[0]::<", $value, $value_ty_suffix, ">")
1104+
);
1105+
}};
1106+
}
10631107

10641108
#[test]
10651109
fn demangle_crate_with_leading_digit() {
@@ -1095,49 +1139,29 @@ mod tests {
10951139
}
10961140

10971141
#[test]
1098-
fn demangle_const_generics() {
1142+
fn demangle_const_generics_preview() {
10991143
// NOTE(eddyb) this was hand-written, before rustc had working
11001144
// const generics support (but the mangling format did include them).
11011145
t_nohash_type!(
11021146
"INtC8arrayvec8ArrayVechKj7b_E",
11031147
"arrayvec::ArrayVec<u8, 123>"
11041148
);
1105-
t_nohash!(
1106-
"_RMCs4fqI2P2rA04_13const_genericINtB0_8UnsignedKhb_E",
1107-
"<const_generic::Unsigned<11>>"
1108-
);
1109-
t_nohash!(
1110-
"_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKs98_E",
1111-
"<const_generic::Signed<152>>"
1112-
);
1113-
t_nohash!(
1114-
"_RMCs4fqI2P2rA04_13const_genericINtB0_6SignedKanb_E",
1115-
"<const_generic::Signed<-11>>"
1116-
);
1117-
t_nohash!(
1118-
"_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb0_E",
1119-
"<const_generic::Bool<false>>"
1120-
);
1121-
t_nohash!(
1122-
"_RMCs4fqI2P2rA04_13const_genericINtB0_4BoolKb1_E",
1123-
"<const_generic::Bool<true>>"
1124-
);
1125-
t_nohash!(
1126-
"_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc76_E",
1127-
"<const_generic::Char<'v'>>"
1128-
);
1129-
t_nohash!(
1130-
"_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKca_E",
1131-
"<const_generic::Char<'\\n'>>"
1132-
);
1133-
t_nohash!(
1134-
"_RMCs4fqI2P2rA04_13const_genericINtB0_4CharKc2202_E",
1135-
"<const_generic::Char<'∂'>>"
1136-
);
1137-
t_nohash!(
1138-
"_RNvNvMCs4fqI2P2rA04_13const_genericINtB4_3FooKpE3foo3FOO",
1139-
"<const_generic::Foo<_>>::foo::FOO"
1140-
);
1149+
t_const_suffixed!("j7b_", "123", "usize");
1150+
}
1151+
1152+
#[test]
1153+
fn demangle_min_const_generics() {
1154+
t_const!("p", "_");
1155+
t_const_suffixed!("hb_", "11", "u8");
1156+
t_const_suffixed!("off00ff00ff00ff00ff_", "0xff00ff00ff00ff00ff", "u128");
1157+
t_const_suffixed!("s98_", "152", "i16");
1158+
t_const_suffixed!("anb_", "-11", "i8");
1159+
t_const!("b0_", "false");
1160+
t_const!("b1_", "true");
1161+
t_const!("c76_", "'v'");
1162+
t_const!("c22_", r#"'"'"#);
1163+
t_const!("ca_", "'\\n'");
1164+
t_const!("c2202_", "'∂'");
11411165
}
11421166

11431167
#[test]

0 commit comments

Comments
 (0)