17310403eSTomasz Miąsko //===--- RustDemangle.cpp ---------------------------------------*- C++ -*-===// 27310403eSTomasz Miąsko // 37310403eSTomasz Miąsko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47310403eSTomasz Miąsko // See https://llvm.org/LICENSE.txt for license information. 57310403eSTomasz Miąsko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67310403eSTomasz Miąsko // 77310403eSTomasz Miąsko //===----------------------------------------------------------------------===// 87310403eSTomasz Miąsko // 97310403eSTomasz Miąsko // This file defines a demangler for Rust v0 mangled symbols as specified in 107310403eSTomasz Miąsko // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html 117310403eSTomasz Miąsko // 127310403eSTomasz Miąsko //===----------------------------------------------------------------------===// 137310403eSTomasz Miąsko 147310403eSTomasz Miąsko #include "llvm/Demangle/RustDemangle.h" 157310403eSTomasz Miąsko #include "llvm/Demangle/Demangle.h" 167310403eSTomasz Miąsko 177310403eSTomasz Miąsko #include <algorithm> 187310403eSTomasz Miąsko #include <cassert> 197310403eSTomasz Miąsko #include <cstring> 207310403eSTomasz Miąsko #include <limits> 217310403eSTomasz Miąsko 227310403eSTomasz Miąsko using namespace llvm; 237310403eSTomasz Miąsko using namespace rust_demangle; 247310403eSTomasz Miąsko 257310403eSTomasz Miąsko char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N, 267310403eSTomasz Miąsko int *Status) { 277310403eSTomasz Miąsko if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { 287310403eSTomasz Miąsko if (Status != nullptr) 297310403eSTomasz Miąsko *Status = demangle_invalid_args; 307310403eSTomasz Miąsko return nullptr; 317310403eSTomasz Miąsko } 327310403eSTomasz Miąsko 337310403eSTomasz Miąsko // Return early if mangled name doesn't look like a Rust symbol. 347310403eSTomasz Miąsko StringView Mangled(MangledName); 357310403eSTomasz Miąsko if (!Mangled.startsWith("_R")) { 367310403eSTomasz Miąsko if (Status != nullptr) 377310403eSTomasz Miąsko *Status = demangle_invalid_mangled_name; 387310403eSTomasz Miąsko return nullptr; 397310403eSTomasz Miąsko } 407310403eSTomasz Miąsko 417310403eSTomasz Miąsko Demangler D; 427310403eSTomasz Miąsko if (!initializeOutputStream(nullptr, nullptr, D.Output, 1024)) { 437310403eSTomasz Miąsko if (Status != nullptr) 447310403eSTomasz Miąsko *Status = demangle_memory_alloc_failure; 457310403eSTomasz Miąsko return nullptr; 467310403eSTomasz Miąsko } 477310403eSTomasz Miąsko 487310403eSTomasz Miąsko if (!D.demangle(Mangled)) { 497310403eSTomasz Miąsko if (Status != nullptr) 507310403eSTomasz Miąsko *Status = demangle_invalid_mangled_name; 517310403eSTomasz Miąsko std::free(D.Output.getBuffer()); 527310403eSTomasz Miąsko return nullptr; 537310403eSTomasz Miąsko } 547310403eSTomasz Miąsko 557310403eSTomasz Miąsko D.Output += '\0'; 567310403eSTomasz Miąsko char *Demangled = D.Output.getBuffer(); 577310403eSTomasz Miąsko size_t DemangledLen = D.Output.getCurrentPosition(); 587310403eSTomasz Miąsko 597310403eSTomasz Miąsko if (Buf != nullptr) { 607310403eSTomasz Miąsko if (DemangledLen <= *N) { 617310403eSTomasz Miąsko std::memcpy(Buf, Demangled, DemangledLen); 627310403eSTomasz Miąsko std::free(Demangled); 637310403eSTomasz Miąsko Demangled = Buf; 647310403eSTomasz Miąsko } else { 657310403eSTomasz Miąsko std::free(Buf); 667310403eSTomasz Miąsko } 677310403eSTomasz Miąsko } 687310403eSTomasz Miąsko 697310403eSTomasz Miąsko if (N != nullptr) 707310403eSTomasz Miąsko *N = DemangledLen; 717310403eSTomasz Miąsko 727310403eSTomasz Miąsko if (Status != nullptr) 737310403eSTomasz Miąsko *Status = demangle_success; 747310403eSTomasz Miąsko 757310403eSTomasz Miąsko return Demangled; 767310403eSTomasz Miąsko } 777310403eSTomasz Miąsko 787310403eSTomasz Miąsko Demangler::Demangler(size_t MaxRecursionLevel) 797310403eSTomasz Miąsko : MaxRecursionLevel(MaxRecursionLevel) {} 807310403eSTomasz Miąsko 817310403eSTomasz Miąsko static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; } 827310403eSTomasz Miąsko 83cd74dd17STomasz Miąsko static inline bool isHexDigit(const char C) { 84cd74dd17STomasz Miąsko return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f'); 85cd74dd17STomasz Miąsko } 86cd74dd17STomasz Miąsko 877310403eSTomasz Miąsko static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; } 887310403eSTomasz Miąsko 897310403eSTomasz Miąsko static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; } 907310403eSTomasz Miąsko 917310403eSTomasz Miąsko /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. 927310403eSTomasz Miąsko static inline bool isValid(const char C) { 937310403eSTomasz Miąsko return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; 947310403eSTomasz Miąsko } 957310403eSTomasz Miąsko 967310403eSTomasz Miąsko // Demangles Rust v0 mangled symbol. Returns true when successful, and false 977310403eSTomasz Miąsko // otherwise. The demangled symbol is stored in Output field. It is 987310403eSTomasz Miąsko // responsibility of the caller to free the memory behind the output stream. 997310403eSTomasz Miąsko // 1007310403eSTomasz Miąsko // <symbol-name> = "_R" <path> [<instantiating-crate>] 1017310403eSTomasz Miąsko bool Demangler::demangle(StringView Mangled) { 1027310403eSTomasz Miąsko Position = 0; 1037310403eSTomasz Miąsko Error = false; 104f0f2a8b2STomasz Miąsko Print = true; 1057310403eSTomasz Miąsko RecursionLevel = 0; 106a67a234eSTomasz Miąsko BoundLifetimes = 0; 1077310403eSTomasz Miąsko 1087310403eSTomasz Miąsko if (!Mangled.consumeFront("_R")) { 1097310403eSTomasz Miąsko Error = true; 1107310403eSTomasz Miąsko return false; 1117310403eSTomasz Miąsko } 112*2a5bb9c8STomasz Miąsko size_t Dot = Mangled.find('.'); 113*2a5bb9c8STomasz Miąsko Input = Mangled.substr(0, Dot); 114*2a5bb9c8STomasz Miąsko StringView Suffix = Mangled.dropFront(Dot); 1157310403eSTomasz Miąsko 11657f40886STomasz Miąsko demanglePath(rust_demangle::InType::No); 1177310403eSTomasz Miąsko 11843929cccSTomasz Miąsko if (Position != Input.size()) { 11943929cccSTomasz Miąsko SwapAndRestore<bool> SavePrint(Print, false); 12043929cccSTomasz Miąsko demanglePath(InType::No); 12143929cccSTomasz Miąsko } 1227310403eSTomasz Miąsko 1237310403eSTomasz Miąsko if (Position != Input.size()) 1247310403eSTomasz Miąsko Error = true; 1257310403eSTomasz Miąsko 126*2a5bb9c8STomasz Miąsko if (!Suffix.empty()) { 127*2a5bb9c8STomasz Miąsko print(" ("); 128*2a5bb9c8STomasz Miąsko print(Suffix); 129*2a5bb9c8STomasz Miąsko print(")"); 130*2a5bb9c8STomasz Miąsko } 131*2a5bb9c8STomasz Miąsko 1327310403eSTomasz Miąsko return !Error; 1337310403eSTomasz Miąsko } 1347310403eSTomasz Miąsko 135619a65e5STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type. When 136619a65e5STomasz Miąsko // LeaveOpen is true, a closing `>` after generic arguments is omitted from the 137619a65e5STomasz Miąsko // output. Return value indicates whether generics arguments have been left 138619a65e5STomasz Miąsko // open. 13906833297STomasz Miąsko // 1407310403eSTomasz Miąsko // <path> = "C" <identifier> // crate root 1417310403eSTomasz Miąsko // | "M" <impl-path> <type> // <T> (inherent impl) 1427310403eSTomasz Miąsko // | "X" <impl-path> <type> <path> // <T as Trait> (trait impl) 1437310403eSTomasz Miąsko // | "Y" <type> <path> // <T as Trait> (trait definition) 1447310403eSTomasz Miąsko // | "N" <ns> <path> <identifier> // ...::ident (nested path) 1457310403eSTomasz Miąsko // | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args) 1467310403eSTomasz Miąsko // | <backref> 1477310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier> 1487310403eSTomasz Miąsko // <ns> = "C" // closure 1497310403eSTomasz Miąsko // | "S" // shim 1507310403eSTomasz Miąsko // | <A-Z> // other special namespaces 1517310403eSTomasz Miąsko // | <a-z> // internal namespaces 152619a65e5STomasz Miąsko bool Demangler::demanglePath(InType InType, LeaveOpen LeaveOpen) { 1537310403eSTomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 1547310403eSTomasz Miąsko Error = true; 155619a65e5STomasz Miąsko return false; 1567310403eSTomasz Miąsko } 15778e94915STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 1587310403eSTomasz Miąsko 1597310403eSTomasz Miąsko switch (consume()) { 1607310403eSTomasz Miąsko case 'C': { 1617310403eSTomasz Miąsko parseOptionalBase62Number('s'); 1627310403eSTomasz Miąsko Identifier Ident = parseIdentifier(); 1637310403eSTomasz Miąsko print(Ident.Name); 1647310403eSTomasz Miąsko break; 1657310403eSTomasz Miąsko } 166f0f2a8b2STomasz Miąsko case 'M': { 16706833297STomasz Miąsko demangleImplPath(InType); 168f0f2a8b2STomasz Miąsko print("<"); 169f0f2a8b2STomasz Miąsko demangleType(); 170f0f2a8b2STomasz Miąsko print(">"); 171f0f2a8b2STomasz Miąsko break; 172f0f2a8b2STomasz Miąsko } 1739fa13800STomasz Miąsko case 'X': { 17406833297STomasz Miąsko demangleImplPath(InType); 1759fa13800STomasz Miąsko print("<"); 1769fa13800STomasz Miąsko demangleType(); 1779fa13800STomasz Miąsko print(" as "); 17857f40886STomasz Miąsko demanglePath(rust_demangle::InType::Yes); 1799fa13800STomasz Miąsko print(">"); 1809fa13800STomasz Miąsko break; 1819fa13800STomasz Miąsko } 182f933f7fbSTomasz Miąsko case 'Y': { 183f933f7fbSTomasz Miąsko print("<"); 184f933f7fbSTomasz Miąsko demangleType(); 185f933f7fbSTomasz Miąsko print(" as "); 18657f40886STomasz Miąsko demanglePath(rust_demangle::InType::Yes); 187f933f7fbSTomasz Miąsko print(">"); 188f933f7fbSTomasz Miąsko break; 189f933f7fbSTomasz Miąsko } 1907310403eSTomasz Miąsko case 'N': { 1917310403eSTomasz Miąsko char NS = consume(); 1927310403eSTomasz Miąsko if (!isLower(NS) && !isUpper(NS)) { 1937310403eSTomasz Miąsko Error = true; 1947310403eSTomasz Miąsko break; 1957310403eSTomasz Miąsko } 19606833297STomasz Miąsko demanglePath(InType); 1977310403eSTomasz Miąsko 19878e94915STomasz Miąsko uint64_t Disambiguator = parseOptionalBase62Number('s'); 1997310403eSTomasz Miąsko Identifier Ident = parseIdentifier(); 2007310403eSTomasz Miąsko 20178e94915STomasz Miąsko if (isUpper(NS)) { 20278e94915STomasz Miąsko // Special namespaces 20378e94915STomasz Miąsko print("::{"); 20478e94915STomasz Miąsko if (NS == 'C') 20578e94915STomasz Miąsko print("closure"); 20678e94915STomasz Miąsko else if (NS == 'S') 20778e94915STomasz Miąsko print("shim"); 20878e94915STomasz Miąsko else 20978e94915STomasz Miąsko print(NS); 2107310403eSTomasz Miąsko if (!Ident.empty()) { 21178e94915STomasz Miąsko print(":"); 21278e94915STomasz Miąsko print(Ident.Name); 21378e94915STomasz Miąsko } 21478e94915STomasz Miąsko print('#'); 21578e94915STomasz Miąsko printDecimalNumber(Disambiguator); 21678e94915STomasz Miąsko print('}'); 21778e94915STomasz Miąsko } else { 21878e94915STomasz Miąsko // Implementation internal namespaces. 21978e94915STomasz Miąsko if (!Ident.empty()) { 2207310403eSTomasz Miąsko print("::"); 2217310403eSTomasz Miąsko print(Ident.Name); 2227310403eSTomasz Miąsko } 22378e94915STomasz Miąsko } 2247310403eSTomasz Miąsko break; 2257310403eSTomasz Miąsko } 2262961f863STomasz Miąsko case 'I': { 22706833297STomasz Miąsko demanglePath(InType); 22806833297STomasz Miąsko // Omit "::" when in a type, where it is optional. 22957f40886STomasz Miąsko if (InType == rust_demangle::InType::No) 23006833297STomasz Miąsko print("::"); 23106833297STomasz Miąsko print("<"); 2322961f863STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 2332961f863STomasz Miąsko if (I > 0) 2342961f863STomasz Miąsko print(", "); 2352961f863STomasz Miąsko demangleGenericArg(); 2362961f863STomasz Miąsko } 237619a65e5STomasz Miąsko if (LeaveOpen == rust_demangle::LeaveOpen::Yes) 238619a65e5STomasz Miąsko return true; 239619a65e5STomasz Miąsko else 2402961f863STomasz Miąsko print(">"); 2412961f863STomasz Miąsko break; 2422961f863STomasz Miąsko } 24382b7e822STomasz Miąsko case 'B': { 24482b7e822STomasz Miąsko bool IsOpen = false; 24582b7e822STomasz Miąsko demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); }); 24682b7e822STomasz Miąsko return IsOpen; 24782b7e822STomasz Miąsko } 2487310403eSTomasz Miąsko default: 2497310403eSTomasz Miąsko Error = true; 2507310403eSTomasz Miąsko break; 2517310403eSTomasz Miąsko } 252619a65e5STomasz Miąsko 253619a65e5STomasz Miąsko return false; 2547310403eSTomasz Miąsko } 2557310403eSTomasz Miąsko 256f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path> 257f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number> 25806833297STomasz Miąsko void Demangler::demangleImplPath(InType InType) { 259f0f2a8b2STomasz Miąsko SwapAndRestore<bool> SavePrint(Print, false); 260f0f2a8b2STomasz Miąsko parseOptionalBase62Number('s'); 26106833297STomasz Miąsko demanglePath(InType); 262f0f2a8b2STomasz Miąsko } 263f0f2a8b2STomasz Miąsko 2642961f863STomasz Miąsko // <generic-arg> = <lifetime> 2652961f863STomasz Miąsko // | <type> 2662961f863STomasz Miąsko // | "K" <const> 2672961f863STomasz Miąsko // <lifetime> = "L" <base-62-number> 2682961f863STomasz Miąsko void Demangler::demangleGenericArg() { 269a67a234eSTomasz Miąsko if (consumeIf('L')) 270a67a234eSTomasz Miąsko printLifetime(parseBase62Number()); 271a67a234eSTomasz Miąsko else if (consumeIf('K')) 272cd74dd17STomasz Miąsko demangleConst(); 273cd74dd17STomasz Miąsko else 2742961f863STomasz Miąsko demangleType(); 2752961f863STomasz Miąsko } 2762961f863STomasz Miąsko 2772961f863STomasz Miąsko // <basic-type> = "a" // i8 2782961f863STomasz Miąsko // | "b" // bool 2792961f863STomasz Miąsko // | "c" // char 2802961f863STomasz Miąsko // | "d" // f64 2812961f863STomasz Miąsko // | "e" // str 2822961f863STomasz Miąsko // | "f" // f32 2832961f863STomasz Miąsko // | "h" // u8 2842961f863STomasz Miąsko // | "i" // isize 2852961f863STomasz Miąsko // | "j" // usize 2862961f863STomasz Miąsko // | "l" // i32 2872961f863STomasz Miąsko // | "m" // u32 2882961f863STomasz Miąsko // | "n" // i128 2892961f863STomasz Miąsko // | "o" // u128 2902961f863STomasz Miąsko // | "s" // i16 2912961f863STomasz Miąsko // | "t" // u16 2922961f863STomasz Miąsko // | "u" // () 2932961f863STomasz Miąsko // | "v" // ... 2942961f863STomasz Miąsko // | "x" // i64 2952961f863STomasz Miąsko // | "y" // u64 2962961f863STomasz Miąsko // | "z" // ! 2972961f863STomasz Miąsko // | "p" // placeholder (e.g. for generic params), shown as _ 298cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) { 299cd74dd17STomasz Miąsko switch (C) { 300cd74dd17STomasz Miąsko case 'a': 301cd74dd17STomasz Miąsko Type = BasicType::I8; 302cd74dd17STomasz Miąsko return true; 303cd74dd17STomasz Miąsko case 'b': 304cd74dd17STomasz Miąsko Type = BasicType::Bool; 305cd74dd17STomasz Miąsko return true; 306cd74dd17STomasz Miąsko case 'c': 307cd74dd17STomasz Miąsko Type = BasicType::Char; 308cd74dd17STomasz Miąsko return true; 309cd74dd17STomasz Miąsko case 'd': 310cd74dd17STomasz Miąsko Type = BasicType::F64; 311cd74dd17STomasz Miąsko return true; 312cd74dd17STomasz Miąsko case 'e': 313cd74dd17STomasz Miąsko Type = BasicType::Str; 314cd74dd17STomasz Miąsko return true; 315cd74dd17STomasz Miąsko case 'f': 316cd74dd17STomasz Miąsko Type = BasicType::F32; 317cd74dd17STomasz Miąsko return true; 318cd74dd17STomasz Miąsko case 'h': 319cd74dd17STomasz Miąsko Type = BasicType::U8; 320cd74dd17STomasz Miąsko return true; 321cd74dd17STomasz Miąsko case 'i': 322cd74dd17STomasz Miąsko Type = BasicType::ISize; 323cd74dd17STomasz Miąsko return true; 324cd74dd17STomasz Miąsko case 'j': 325cd74dd17STomasz Miąsko Type = BasicType::USize; 326cd74dd17STomasz Miąsko return true; 327cd74dd17STomasz Miąsko case 'l': 328cd74dd17STomasz Miąsko Type = BasicType::I32; 329cd74dd17STomasz Miąsko return true; 330cd74dd17STomasz Miąsko case 'm': 331cd74dd17STomasz Miąsko Type = BasicType::U32; 332cd74dd17STomasz Miąsko return true; 333cd74dd17STomasz Miąsko case 'n': 334cd74dd17STomasz Miąsko Type = BasicType::I128; 335cd74dd17STomasz Miąsko return true; 336cd74dd17STomasz Miąsko case 'o': 337cd74dd17STomasz Miąsko Type = BasicType::U128; 338cd74dd17STomasz Miąsko return true; 339cd74dd17STomasz Miąsko case 'p': 340cd74dd17STomasz Miąsko Type = BasicType::Placeholder; 341cd74dd17STomasz Miąsko return true; 342cd74dd17STomasz Miąsko case 's': 343cd74dd17STomasz Miąsko Type = BasicType::I16; 344cd74dd17STomasz Miąsko return true; 345cd74dd17STomasz Miąsko case 't': 346cd74dd17STomasz Miąsko Type = BasicType::U16; 347cd74dd17STomasz Miąsko return true; 348cd74dd17STomasz Miąsko case 'u': 349cd74dd17STomasz Miąsko Type = BasicType::Unit; 350cd74dd17STomasz Miąsko return true; 351cd74dd17STomasz Miąsko case 'v': 352cd74dd17STomasz Miąsko Type = BasicType::Variadic; 353cd74dd17STomasz Miąsko return true; 354cd74dd17STomasz Miąsko case 'x': 355cd74dd17STomasz Miąsko Type = BasicType::I64; 356cd74dd17STomasz Miąsko return true; 357cd74dd17STomasz Miąsko case 'y': 358cd74dd17STomasz Miąsko Type = BasicType::U64; 359cd74dd17STomasz Miąsko return true; 360cd74dd17STomasz Miąsko case 'z': 361cd74dd17STomasz Miąsko Type = BasicType::Never; 362cd74dd17STomasz Miąsko return true; 363cd74dd17STomasz Miąsko default: 364cd74dd17STomasz Miąsko return false; 365cd74dd17STomasz Miąsko } 366cd74dd17STomasz Miąsko } 367cd74dd17STomasz Miąsko 368cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) { 369cd74dd17STomasz Miąsko switch (Type) { 370cd74dd17STomasz Miąsko case BasicType::Bool: 371cd74dd17STomasz Miąsko print("bool"); 372cd74dd17STomasz Miąsko break; 373cd74dd17STomasz Miąsko case BasicType::Char: 374cd74dd17STomasz Miąsko print("char"); 375cd74dd17STomasz Miąsko break; 376cd74dd17STomasz Miąsko case BasicType::I8: 377cd74dd17STomasz Miąsko print("i8"); 378cd74dd17STomasz Miąsko break; 379cd74dd17STomasz Miąsko case BasicType::I16: 380cd74dd17STomasz Miąsko print("i16"); 381cd74dd17STomasz Miąsko break; 382cd74dd17STomasz Miąsko case BasicType::I32: 383cd74dd17STomasz Miąsko print("i32"); 384cd74dd17STomasz Miąsko break; 385cd74dd17STomasz Miąsko case BasicType::I64: 386cd74dd17STomasz Miąsko print("i64"); 387cd74dd17STomasz Miąsko break; 388cd74dd17STomasz Miąsko case BasicType::I128: 389cd74dd17STomasz Miąsko print("i128"); 390cd74dd17STomasz Miąsko break; 391cd74dd17STomasz Miąsko case BasicType::ISize: 392cd74dd17STomasz Miąsko print("isize"); 393cd74dd17STomasz Miąsko break; 394cd74dd17STomasz Miąsko case BasicType::U8: 395cd74dd17STomasz Miąsko print("u8"); 396cd74dd17STomasz Miąsko break; 397cd74dd17STomasz Miąsko case BasicType::U16: 398cd74dd17STomasz Miąsko print("u16"); 399cd74dd17STomasz Miąsko break; 400cd74dd17STomasz Miąsko case BasicType::U32: 401cd74dd17STomasz Miąsko print("u32"); 402cd74dd17STomasz Miąsko break; 403cd74dd17STomasz Miąsko case BasicType::U64: 404cd74dd17STomasz Miąsko print("u64"); 405cd74dd17STomasz Miąsko break; 406cd74dd17STomasz Miąsko case BasicType::U128: 407cd74dd17STomasz Miąsko print("u128"); 408cd74dd17STomasz Miąsko break; 409cd74dd17STomasz Miąsko case BasicType::USize: 410cd74dd17STomasz Miąsko print("usize"); 411cd74dd17STomasz Miąsko break; 412cd74dd17STomasz Miąsko case BasicType::F32: 413cd74dd17STomasz Miąsko print("f32"); 414cd74dd17STomasz Miąsko break; 415cd74dd17STomasz Miąsko case BasicType::F64: 416cd74dd17STomasz Miąsko print("f64"); 417cd74dd17STomasz Miąsko break; 418cd74dd17STomasz Miąsko case BasicType::Str: 419cd74dd17STomasz Miąsko print("str"); 420cd74dd17STomasz Miąsko break; 421cd74dd17STomasz Miąsko case BasicType::Placeholder: 422cd74dd17STomasz Miąsko print("_"); 423cd74dd17STomasz Miąsko break; 424cd74dd17STomasz Miąsko case BasicType::Unit: 425cd74dd17STomasz Miąsko print("()"); 426cd74dd17STomasz Miąsko break; 427cd74dd17STomasz Miąsko case BasicType::Variadic: 428cd74dd17STomasz Miąsko print("..."); 429cd74dd17STomasz Miąsko break; 430cd74dd17STomasz Miąsko case BasicType::Never: 431cd74dd17STomasz Miąsko print("!"); 432cd74dd17STomasz Miąsko break; 433cd74dd17STomasz Miąsko } 4342961f863STomasz Miąsko } 4352961f863STomasz Miąsko 4362961f863STomasz Miąsko // <type> = | <basic-type> 4372961f863STomasz Miąsko // | <path> // named type 4382961f863STomasz Miąsko // | "A" <type> <const> // [T; N] 4392961f863STomasz Miąsko // | "S" <type> // [T] 4402961f863STomasz Miąsko // | "T" {<type>} "E" // (T1, T2, T3, ...) 4412961f863STomasz Miąsko // | "R" [<lifetime>] <type> // &T 4422961f863STomasz Miąsko // | "Q" [<lifetime>] <type> // &mut T 4432961f863STomasz Miąsko // | "P" <type> // *const T 4442961f863STomasz Miąsko // | "O" <type> // *mut T 4452961f863STomasz Miąsko // | "F" <fn-sig> // fn(...) -> ... 4462961f863STomasz Miąsko // | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a 4472961f863STomasz Miąsko // | <backref> // backref 4482961f863STomasz Miąsko void Demangler::demangleType() { 44944d63c57STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 45044d63c57STomasz Miąsko Error = true; 45144d63c57STomasz Miąsko return; 45244d63c57STomasz Miąsko } 45344d63c57STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 45406833297STomasz Miąsko 45544d63c57STomasz Miąsko size_t Start = Position; 456b42400ccSTomasz Miąsko char C = consume(); 457b42400ccSTomasz Miąsko BasicType Type; 458b42400ccSTomasz Miąsko if (parseBasicType(C, Type)) 459b42400ccSTomasz Miąsko return printBasicType(Type); 460b42400ccSTomasz Miąsko 461b42400ccSTomasz Miąsko switch (C) { 462b42400ccSTomasz Miąsko case 'A': 463b42400ccSTomasz Miąsko print("["); 464b42400ccSTomasz Miąsko demangleType(); 465b42400ccSTomasz Miąsko print("; "); 466b42400ccSTomasz Miąsko demangleConst(); 467b42400ccSTomasz Miąsko print("]"); 468b42400ccSTomasz Miąsko break; 469a84c65c2STomasz Miąsko case 'S': 470a84c65c2STomasz Miąsko print("["); 471a84c65c2STomasz Miąsko demangleType(); 472a84c65c2STomasz Miąsko print("]"); 473a84c65c2STomasz Miąsko break; 474774de7a0STomasz Miąsko case 'T': { 475774de7a0STomasz Miąsko print("("); 476774de7a0STomasz Miąsko size_t I = 0; 477774de7a0STomasz Miąsko for (; !Error && !consumeIf('E'); ++I) { 478774de7a0STomasz Miąsko if (I > 0) 479774de7a0STomasz Miąsko print(", "); 480774de7a0STomasz Miąsko demangleType(); 481774de7a0STomasz Miąsko } 482774de7a0STomasz Miąsko if (I == 1) 483774de7a0STomasz Miąsko print(","); 484774de7a0STomasz Miąsko print(")"); 485774de7a0STomasz Miąsko break; 486774de7a0STomasz Miąsko } 487e4fa6c95STomasz Miąsko case 'R': 488e4fa6c95STomasz Miąsko case 'Q': 489a67a234eSTomasz Miąsko print('&'); 490a67a234eSTomasz Miąsko if (consumeIf('L')) { 491a67a234eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) { 492a67a234eSTomasz Miąsko printLifetime(Lifetime); 493a67a234eSTomasz Miąsko print(' '); 494a67a234eSTomasz Miąsko } 495a67a234eSTomasz Miąsko } 496a67a234eSTomasz Miąsko if (C == 'Q') 497a67a234eSTomasz Miąsko print("mut "); 498e4fa6c95STomasz Miąsko demangleType(); 499e4fa6c95STomasz Miąsko break; 5006aac5633STomasz Miąsko case 'P': 5016aac5633STomasz Miąsko print("*const "); 5026aac5633STomasz Miąsko demangleType(); 5036aac5633STomasz Miąsko break; 5046aac5633STomasz Miąsko case 'O': 5056aac5633STomasz Miąsko print("*mut "); 5066aac5633STomasz Miąsko demangleType(); 5076aac5633STomasz Miąsko break; 50875cc1cf0STomasz Miąsko case 'F': 50975cc1cf0STomasz Miąsko demangleFnSig(); 51075cc1cf0STomasz Miąsko break; 51189615a5eSTomasz Miąsko case 'D': 51289615a5eSTomasz Miąsko demangleDynBounds(); 51389615a5eSTomasz Miąsko if (consumeIf('L')) { 51489615a5eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) { 51589615a5eSTomasz Miąsko print(" + "); 51689615a5eSTomasz Miąsko printLifetime(Lifetime); 51789615a5eSTomasz Miąsko } 51889615a5eSTomasz Miąsko } else { 51989615a5eSTomasz Miąsko Error = true; 52089615a5eSTomasz Miąsko } 52189615a5eSTomasz Miąsko break; 52244d63c57STomasz Miąsko case 'B': 52344d63c57STomasz Miąsko demangleBackref([&] { demangleType(); }); 52444d63c57STomasz Miąsko break; 525b42400ccSTomasz Miąsko default: 526b42400ccSTomasz Miąsko Position = Start; 52757f40886STomasz Miąsko demanglePath(rust_demangle::InType::Yes); 528b42400ccSTomasz Miąsko break; 529b42400ccSTomasz Miąsko } 530cd74dd17STomasz Miąsko } 531cd74dd17STomasz Miąsko 53275cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type> 53375cc1cf0STomasz Miąsko // <abi> = "C" 53475cc1cf0STomasz Miąsko // | <undisambiguated-identifier> 53575cc1cf0STomasz Miąsko void Demangler::demangleFnSig() { 536a67a234eSTomasz Miąsko SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 537a67a234eSTomasz Miąsko demangleOptionalBinder(); 53875cc1cf0STomasz Miąsko 53975cc1cf0STomasz Miąsko if (consumeIf('U')) 54075cc1cf0STomasz Miąsko print("unsafe "); 54175cc1cf0STomasz Miąsko 54275cc1cf0STomasz Miąsko if (consumeIf('K')) { 54375cc1cf0STomasz Miąsko print("extern \""); 54475cc1cf0STomasz Miąsko if (consumeIf('C')) { 54575cc1cf0STomasz Miąsko print("C"); 54675cc1cf0STomasz Miąsko } else { 54775cc1cf0STomasz Miąsko Identifier Ident = parseIdentifier(); 54875cc1cf0STomasz Miąsko for (char C : Ident.Name) { 54975cc1cf0STomasz Miąsko // When mangling ABI string, the "-" is replaced with "_". 55075cc1cf0STomasz Miąsko if (C == '_') 55175cc1cf0STomasz Miąsko C = '-'; 55275cc1cf0STomasz Miąsko print(C); 55375cc1cf0STomasz Miąsko } 55475cc1cf0STomasz Miąsko } 55575cc1cf0STomasz Miąsko print("\" "); 55675cc1cf0STomasz Miąsko } 55775cc1cf0STomasz Miąsko 55875cc1cf0STomasz Miąsko print("fn("); 55975cc1cf0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 56075cc1cf0STomasz Miąsko if (I > 0) 56175cc1cf0STomasz Miąsko print(", "); 56275cc1cf0STomasz Miąsko demangleType(); 56375cc1cf0STomasz Miąsko } 56475cc1cf0STomasz Miąsko print(")"); 56575cc1cf0STomasz Miąsko 56675cc1cf0STomasz Miąsko if (consumeIf('u')) { 56775cc1cf0STomasz Miąsko // Skip the unit type from the output. 56875cc1cf0STomasz Miąsko } else { 56975cc1cf0STomasz Miąsko print(" -> "); 57075cc1cf0STomasz Miąsko demangleType(); 57175cc1cf0STomasz Miąsko } 57275cc1cf0STomasz Miąsko } 57375cc1cf0STomasz Miąsko 57489615a5eSTomasz Miąsko // <dyn-bounds> = [<binder>] {<dyn-trait>} "E" 57589615a5eSTomasz Miąsko void Demangler::demangleDynBounds() { 57689615a5eSTomasz Miąsko SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 57789615a5eSTomasz Miąsko print("dyn "); 57889615a5eSTomasz Miąsko demangleOptionalBinder(); 5791499afa0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 5801499afa0STomasz Miąsko if (I > 0) 5811499afa0STomasz Miąsko print(" + "); 5821499afa0STomasz Miąsko demangleDynTrait(); 5831499afa0STomasz Miąsko } 5841499afa0STomasz Miąsko } 5851499afa0STomasz Miąsko 5861499afa0STomasz Miąsko // <dyn-trait> = <path> {<dyn-trait-assoc-binding>} 5871499afa0STomasz Miąsko // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type> 5881499afa0STomasz Miąsko void Demangler::demangleDynTrait() { 589619a65e5STomasz Miąsko bool IsOpen = demanglePath(InType::Yes, LeaveOpen::Yes); 590619a65e5STomasz Miąsko while (!Error && consumeIf('p')) { 591619a65e5STomasz Miąsko if (!IsOpen) { 592619a65e5STomasz Miąsko IsOpen = true; 593619a65e5STomasz Miąsko print('<'); 594619a65e5STomasz Miąsko } else { 595619a65e5STomasz Miąsko print(", "); 596619a65e5STomasz Miąsko } 597619a65e5STomasz Miąsko print(parseIdentifier().Name); 598619a65e5STomasz Miąsko print(" = "); 599619a65e5STomasz Miąsko demangleType(); 600619a65e5STomasz Miąsko } 601619a65e5STomasz Miąsko if (IsOpen) 602619a65e5STomasz Miąsko print(">"); 60389615a5eSTomasz Miąsko } 60489615a5eSTomasz Miąsko 605a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes. 606a67a234eSTomasz Miąsko // 607a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number> 608a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() { 609a67a234eSTomasz Miąsko uint64_t Binder = parseOptionalBase62Number('G'); 610a67a234eSTomasz Miąsko if (Error || Binder == 0) 611a67a234eSTomasz Miąsko return; 612a67a234eSTomasz Miąsko 613a67a234eSTomasz Miąsko // In valid inputs each bound lifetime is referenced later. Referencing a 614a67a234eSTomasz Miąsko // lifetime requires at least one byte of input. Reject inputs that are too 615a67a234eSTomasz Miąsko // short to reference all bound lifetimes. Otherwise demangling of invalid 616a67a234eSTomasz Miąsko // binders could generate excessive amounts of output. 617a67a234eSTomasz Miąsko if (Binder >= Input.size() - BoundLifetimes) { 618a67a234eSTomasz Miąsko Error = true; 619a67a234eSTomasz Miąsko return; 620a67a234eSTomasz Miąsko } 621a67a234eSTomasz Miąsko 622a67a234eSTomasz Miąsko print("for<"); 623a67a234eSTomasz Miąsko for (size_t I = 0; I != Binder; ++I) { 624a67a234eSTomasz Miąsko BoundLifetimes += 1; 625a67a234eSTomasz Miąsko if (I > 0) 626a67a234eSTomasz Miąsko print(", "); 627a67a234eSTomasz Miąsko printLifetime(1); 628a67a234eSTomasz Miąsko } 629a67a234eSTomasz Miąsko print("> "); 630a67a234eSTomasz Miąsko } 631a67a234eSTomasz Miąsko 632cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data> 633cd74dd17STomasz Miąsko // | "p" // placeholder 634cd74dd17STomasz Miąsko // | <backref> 635cd74dd17STomasz Miąsko void Demangler::demangleConst() { 636f9a79356STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 637f9a79356STomasz Miąsko Error = true; 638f9a79356STomasz Miąsko return; 639f9a79356STomasz Miąsko } 640f9a79356STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 641f9a79356STomasz Miąsko 642f9a79356STomasz Miąsko char C = consume(); 643cd74dd17STomasz Miąsko BasicType Type; 644f9a79356STomasz Miąsko if (parseBasicType(C, Type)) { 645cd74dd17STomasz Miąsko switch (Type) { 646cd74dd17STomasz Miąsko case BasicType::I8: 647cd74dd17STomasz Miąsko case BasicType::I16: 648cd74dd17STomasz Miąsko case BasicType::I32: 649cd74dd17STomasz Miąsko case BasicType::I64: 650cd74dd17STomasz Miąsko case BasicType::I128: 651cd74dd17STomasz Miąsko case BasicType::ISize: 652cd74dd17STomasz Miąsko case BasicType::U8: 653cd74dd17STomasz Miąsko case BasicType::U16: 654cd74dd17STomasz Miąsko case BasicType::U32: 655cd74dd17STomasz Miąsko case BasicType::U64: 656cd74dd17STomasz Miąsko case BasicType::U128: 657cd74dd17STomasz Miąsko case BasicType::USize: 658cd74dd17STomasz Miąsko demangleConstInt(); 659cd74dd17STomasz Miąsko break; 660fc0f2bb9STomasz Miąsko case BasicType::Bool: 661fc0f2bb9STomasz Miąsko demangleConstBool(); 662fc0f2bb9STomasz Miąsko break; 6632ba49f6aSTomasz Miąsko case BasicType::Char: 6642ba49f6aSTomasz Miąsko demangleConstChar(); 6652ba49f6aSTomasz Miąsko break; 666cd74dd17STomasz Miąsko case BasicType::Placeholder: 667cd74dd17STomasz Miąsko print('_'); 668cd74dd17STomasz Miąsko break; 669cd74dd17STomasz Miąsko default: 6702961f863STomasz Miąsko Error = true; 671cd74dd17STomasz Miąsko break; 672cd74dd17STomasz Miąsko } 673f9a79356STomasz Miąsko } else if (C == 'B') { 674f9a79356STomasz Miąsko demangleBackref([&] { demangleConst(); }); 675cd74dd17STomasz Miąsko } else { 676cd74dd17STomasz Miąsko Error = true; 677cd74dd17STomasz Miąsko } 678cd74dd17STomasz Miąsko } 679cd74dd17STomasz Miąsko 680cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number> 681cd74dd17STomasz Miąsko void Demangler::demangleConstInt() { 682cd74dd17STomasz Miąsko if (consumeIf('n')) 683cd74dd17STomasz Miąsko print('-'); 684cd74dd17STomasz Miąsko 685cd74dd17STomasz Miąsko StringView HexDigits; 686cd74dd17STomasz Miąsko uint64_t Value = parseHexNumber(HexDigits); 687cd74dd17STomasz Miąsko if (HexDigits.size() <= 16) { 688cd74dd17STomasz Miąsko printDecimalNumber(Value); 689cd74dd17STomasz Miąsko } else { 690cd74dd17STomasz Miąsko print("0x"); 691cd74dd17STomasz Miąsko print(HexDigits); 6922961f863STomasz Miąsko } 6932961f863STomasz Miąsko } 6942961f863STomasz Miąsko 695fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false 696fc0f2bb9STomasz Miąsko // | "1_" // true 697fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() { 698fc0f2bb9STomasz Miąsko StringView HexDigits; 699fc0f2bb9STomasz Miąsko parseHexNumber(HexDigits); 700fc0f2bb9STomasz Miąsko if (HexDigits == "0") 701fc0f2bb9STomasz Miąsko print("false"); 702fc0f2bb9STomasz Miąsko else if (HexDigits == "1") 703fc0f2bb9STomasz Miąsko print("true"); 704fc0f2bb9STomasz Miąsko else 705fc0f2bb9STomasz Miąsko Error = true; 706fc0f2bb9STomasz Miąsko } 707fc0f2bb9STomasz Miąsko 7082ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character. 7092ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) { 7102ba49f6aSTomasz Miąsko return 0x20 <= CodePoint && CodePoint <= 0x7e; 7112ba49f6aSTomasz Miąsko } 7122ba49f6aSTomasz Miąsko 7132ba49f6aSTomasz Miąsko // <const-data> = <hex-number> 7142ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() { 7152ba49f6aSTomasz Miąsko StringView HexDigits; 7162ba49f6aSTomasz Miąsko uint64_t CodePoint = parseHexNumber(HexDigits); 7172ba49f6aSTomasz Miąsko if (Error || HexDigits.size() > 6) { 7182ba49f6aSTomasz Miąsko Error = true; 7192ba49f6aSTomasz Miąsko return; 7202ba49f6aSTomasz Miąsko } 7212ba49f6aSTomasz Miąsko 7222ba49f6aSTomasz Miąsko print("'"); 7232ba49f6aSTomasz Miąsko switch (CodePoint) { 7242ba49f6aSTomasz Miąsko case '\t': 7252ba49f6aSTomasz Miąsko print(R"(\t)"); 7262ba49f6aSTomasz Miąsko break; 7272ba49f6aSTomasz Miąsko case '\r': 7282ba49f6aSTomasz Miąsko print(R"(\r)"); 7292ba49f6aSTomasz Miąsko break; 7302ba49f6aSTomasz Miąsko case '\n': 7312ba49f6aSTomasz Miąsko print(R"(\n)"); 7322ba49f6aSTomasz Miąsko break; 7332ba49f6aSTomasz Miąsko case '\\': 7342ba49f6aSTomasz Miąsko print(R"(\\)"); 7352ba49f6aSTomasz Miąsko break; 7362ba49f6aSTomasz Miąsko case '"': 7372ba49f6aSTomasz Miąsko print(R"(")"); 7382ba49f6aSTomasz Miąsko break; 7392ba49f6aSTomasz Miąsko case '\'': 7402ba49f6aSTomasz Miąsko print(R"(\')"); 7412ba49f6aSTomasz Miąsko break; 7422ba49f6aSTomasz Miąsko default: 7432ba49f6aSTomasz Miąsko if (isAsciiPrintable(CodePoint)) { 7442ba49f6aSTomasz Miąsko char C = CodePoint; 7452ba49f6aSTomasz Miąsko print(C); 7462ba49f6aSTomasz Miąsko } else { 7472ba49f6aSTomasz Miąsko print(R"(\u{)"); 7482ba49f6aSTomasz Miąsko print(HexDigits); 7492ba49f6aSTomasz Miąsko print('}'); 7502ba49f6aSTomasz Miąsko } 7512ba49f6aSTomasz Miąsko break; 7522ba49f6aSTomasz Miąsko } 7532ba49f6aSTomasz Miąsko print('\''); 7542ba49f6aSTomasz Miąsko } 7552ba49f6aSTomasz Miąsko 7567310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> 7577310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() { 7587310403eSTomasz Miąsko bool Punycode = consumeIf('u'); 7597310403eSTomasz Miąsko uint64_t Bytes = parseDecimalNumber(); 7607310403eSTomasz Miąsko 7617310403eSTomasz Miąsko // Underscore resolves the ambiguity when identifier starts with a decimal 7627310403eSTomasz Miąsko // digit or another underscore. 7637310403eSTomasz Miąsko consumeIf('_'); 7647310403eSTomasz Miąsko 7657310403eSTomasz Miąsko if (Error || Bytes > Input.size() - Position) { 7667310403eSTomasz Miąsko Error = true; 7677310403eSTomasz Miąsko return {}; 7687310403eSTomasz Miąsko } 7697310403eSTomasz Miąsko StringView S = Input.substr(Position, Bytes); 7707310403eSTomasz Miąsko Position += Bytes; 7717310403eSTomasz Miąsko 7727310403eSTomasz Miąsko if (!std::all_of(S.begin(), S.end(), isValid)) { 7737310403eSTomasz Miąsko Error = true; 7747310403eSTomasz Miąsko return {}; 7757310403eSTomasz Miąsko } 7767310403eSTomasz Miąsko 7777310403eSTomasz Miąsko return {S, Punycode}; 7787310403eSTomasz Miąsko } 7797310403eSTomasz Miąsko 7807310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using 781a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise 782a67a234eSTomasz Miąsko // 783a67a234eSTomasz Miąsko // This function is indended for parsing disambiguators and binders which when 784a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded 785a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is 786a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0. 78778e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) { 78878e94915STomasz Miąsko if (!consumeIf(Tag)) 78978e94915STomasz Miąsko return 0; 79078e94915STomasz Miąsko 79178e94915STomasz Miąsko uint64_t N = parseBase62Number(); 79278e94915STomasz Miąsko if (Error || !addAssign(N, 1)) 79378e94915STomasz Miąsko return 0; 79478e94915STomasz Miąsko 79578e94915STomasz Miąsko return N; 7967310403eSTomasz Miąsko } 7977310403eSTomasz Miąsko 7987310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by 7997310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, 8007310403eSTomasz Miąsko // "1_" encodes 2, etc. 8017310403eSTomasz Miąsko // 8027310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_" 8037310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() { 8047310403eSTomasz Miąsko if (consumeIf('_')) 8057310403eSTomasz Miąsko return 0; 8067310403eSTomasz Miąsko 8077310403eSTomasz Miąsko uint64_t Value = 0; 8087310403eSTomasz Miąsko 8097310403eSTomasz Miąsko while (true) { 8107310403eSTomasz Miąsko uint64_t Digit; 8117310403eSTomasz Miąsko char C = consume(); 8127310403eSTomasz Miąsko 8137310403eSTomasz Miąsko if (C == '_') { 8147310403eSTomasz Miąsko break; 8157310403eSTomasz Miąsko } else if (isDigit(C)) { 8167310403eSTomasz Miąsko Digit = C - '0'; 8177310403eSTomasz Miąsko } else if (isLower(C)) { 8187310403eSTomasz Miąsko Digit = 10 + (C - 'a'); 8197310403eSTomasz Miąsko } else if (isUpper(C)) { 8207310403eSTomasz Miąsko Digit = 10 + 26 + (C - 'A'); 8217310403eSTomasz Miąsko } else { 8227310403eSTomasz Miąsko Error = true; 8237310403eSTomasz Miąsko return 0; 8247310403eSTomasz Miąsko } 8257310403eSTomasz Miąsko 8267310403eSTomasz Miąsko if (!mulAssign(Value, 62)) 8277310403eSTomasz Miąsko return 0; 8287310403eSTomasz Miąsko 8297310403eSTomasz Miąsko if (!addAssign(Value, Digit)) 8307310403eSTomasz Miąsko return 0; 8317310403eSTomasz Miąsko } 8327310403eSTomasz Miąsko 8337310403eSTomasz Miąsko if (!addAssign(Value, 1)) 8347310403eSTomasz Miąsko return 0; 8357310403eSTomasz Miąsko 8367310403eSTomasz Miąsko return Value; 8377310403eSTomasz Miąsko } 8387310403eSTomasz Miąsko 8397310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros. 8407310403eSTomasz Miąsko // 8417310403eSTomasz Miąsko // <decimal-number> = "0" 8427310403eSTomasz Miąsko // | <1-9> {<0-9>} 8437310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() { 8447310403eSTomasz Miąsko char C = look(); 8457310403eSTomasz Miąsko if (!isDigit(C)) { 8467310403eSTomasz Miąsko Error = true; 8477310403eSTomasz Miąsko return 0; 8487310403eSTomasz Miąsko } 8497310403eSTomasz Miąsko 8507310403eSTomasz Miąsko if (C == '0') { 8517310403eSTomasz Miąsko consume(); 8527310403eSTomasz Miąsko return 0; 8537310403eSTomasz Miąsko } 8547310403eSTomasz Miąsko 8557310403eSTomasz Miąsko uint64_t Value = 0; 8567310403eSTomasz Miąsko 8577310403eSTomasz Miąsko while (isDigit(look())) { 8587310403eSTomasz Miąsko if (!mulAssign(Value, 10)) { 8597310403eSTomasz Miąsko Error = true; 8607310403eSTomasz Miąsko return 0; 8617310403eSTomasz Miąsko } 8627310403eSTomasz Miąsko 8637310403eSTomasz Miąsko uint64_t D = consume() - '0'; 8647310403eSTomasz Miąsko if (!addAssign(Value, D)) 8657310403eSTomasz Miąsko return 0; 8667310403eSTomasz Miąsko } 8677310403eSTomasz Miąsko 8687310403eSTomasz Miąsko return Value; 8697310403eSTomasz Miąsko } 870cd74dd17STomasz Miąsko 871cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed 872cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if 873cd74dd17STomasz Miąsko // HexDigits.size() > 16. 874cd74dd17STomasz Miąsko // 875cd74dd17STomasz Miąsko // <hex-number> = "0_" 876cd74dd17STomasz Miąsko // | <1-9a-f> {<0-9a-f>} "_" 877cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) { 878cd74dd17STomasz Miąsko size_t Start = Position; 879cd74dd17STomasz Miąsko uint64_t Value = 0; 880cd74dd17STomasz Miąsko 881cd74dd17STomasz Miąsko if (!isHexDigit(look())) 882cd74dd17STomasz Miąsko Error = true; 883cd74dd17STomasz Miąsko 884cd74dd17STomasz Miąsko if (consumeIf('0')) { 885cd74dd17STomasz Miąsko if (!consumeIf('_')) 886cd74dd17STomasz Miąsko Error = true; 887cd74dd17STomasz Miąsko } else { 888cd74dd17STomasz Miąsko while (!Error && !consumeIf('_')) { 889cd74dd17STomasz Miąsko char C = consume(); 890cd74dd17STomasz Miąsko Value *= 16; 891cd74dd17STomasz Miąsko if (isDigit(C)) 892cd74dd17STomasz Miąsko Value += C - '0'; 893cd74dd17STomasz Miąsko else if ('a' <= C && C <= 'f') 894cd74dd17STomasz Miąsko Value += 10 + (C - 'a'); 895cd74dd17STomasz Miąsko else 896cd74dd17STomasz Miąsko Error = true; 897cd74dd17STomasz Miąsko } 898cd74dd17STomasz Miąsko } 899cd74dd17STomasz Miąsko 900cd74dd17STomasz Miąsko if (Error) { 901cd74dd17STomasz Miąsko HexDigits = StringView(); 902cd74dd17STomasz Miąsko return 0; 903cd74dd17STomasz Miąsko } 904cd74dd17STomasz Miąsko 905cd74dd17STomasz Miąsko size_t End = Position - 1; 906cd74dd17STomasz Miąsko assert(Start < End); 907cd74dd17STomasz Miąsko HexDigits = Input.substr(Start, End - Start); 908cd74dd17STomasz Miąsko return Value; 909cd74dd17STomasz Miąsko } 910a67a234eSTomasz Miąsko 911a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices 912a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes 913a67a234eSTomasz Miąsko // bound by one of the enclosing binders. 914a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) { 915a67a234eSTomasz Miąsko if (Index == 0) { 916a67a234eSTomasz Miąsko print("'_"); 917a67a234eSTomasz Miąsko return; 918a67a234eSTomasz Miąsko } 919a67a234eSTomasz Miąsko 920a67a234eSTomasz Miąsko if (Index - 1 >= BoundLifetimes) { 921a67a234eSTomasz Miąsko Error = true; 922a67a234eSTomasz Miąsko return; 923a67a234eSTomasz Miąsko } 924a67a234eSTomasz Miąsko 925a67a234eSTomasz Miąsko uint64_t Depth = BoundLifetimes - Index; 926a67a234eSTomasz Miąsko print('\''); 927a67a234eSTomasz Miąsko if (Depth < 26) { 928a67a234eSTomasz Miąsko char C = 'a' + Depth; 929a67a234eSTomasz Miąsko print(C); 930a67a234eSTomasz Miąsko } else { 931a67a234eSTomasz Miąsko print('z'); 932a67a234eSTomasz Miąsko printDecimalNumber(Depth - 26 + 1); 933a67a234eSTomasz Miąsko } 934a67a234eSTomasz Miąsko } 935