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/Demangle.h" 156cc6ada1STomasz Miąsko #include "llvm/Demangle/StringView.h" 166cc6ada1STomasz Miąsko #include "llvm/Demangle/Utility.h" 177310403eSTomasz Miąsko 187310403eSTomasz Miąsko #include <algorithm> 197310403eSTomasz Miąsko #include <cassert> 206cc6ada1STomasz Miąsko #include <cstdint> 217310403eSTomasz Miąsko #include <cstring> 227310403eSTomasz Miąsko #include <limits> 237310403eSTomasz Miąsko 247310403eSTomasz Miąsko using namespace llvm; 256cc6ada1STomasz Miąsko 26*2e97236aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer; 276cc6ada1STomasz Miąsko using llvm::itanium_demangle::StringView; 286cc6ada1STomasz Miąsko using llvm::itanium_demangle::SwapAndRestore; 296cc6ada1STomasz Miąsko 306cc6ada1STomasz Miąsko namespace { 316cc6ada1STomasz Miąsko 326cc6ada1STomasz Miąsko struct Identifier { 336cc6ada1STomasz Miąsko StringView Name; 346cc6ada1STomasz Miąsko bool Punycode; 356cc6ada1STomasz Miąsko 366cc6ada1STomasz Miąsko bool empty() const { return Name.empty(); } 376cc6ada1STomasz Miąsko }; 386cc6ada1STomasz Miąsko 396cc6ada1STomasz Miąsko enum class BasicType { 406cc6ada1STomasz Miąsko Bool, 416cc6ada1STomasz Miąsko Char, 426cc6ada1STomasz Miąsko I8, 436cc6ada1STomasz Miąsko I16, 446cc6ada1STomasz Miąsko I32, 456cc6ada1STomasz Miąsko I64, 466cc6ada1STomasz Miąsko I128, 476cc6ada1STomasz Miąsko ISize, 486cc6ada1STomasz Miąsko U8, 496cc6ada1STomasz Miąsko U16, 506cc6ada1STomasz Miąsko U32, 516cc6ada1STomasz Miąsko U64, 526cc6ada1STomasz Miąsko U128, 536cc6ada1STomasz Miąsko USize, 546cc6ada1STomasz Miąsko F32, 556cc6ada1STomasz Miąsko F64, 566cc6ada1STomasz Miąsko Str, 576cc6ada1STomasz Miąsko Placeholder, 586cc6ada1STomasz Miąsko Unit, 596cc6ada1STomasz Miąsko Variadic, 606cc6ada1STomasz Miąsko Never, 616cc6ada1STomasz Miąsko }; 626cc6ada1STomasz Miąsko 636cc6ada1STomasz Miąsko enum class IsInType { 646cc6ada1STomasz Miąsko No, 656cc6ada1STomasz Miąsko Yes, 666cc6ada1STomasz Miąsko }; 676cc6ada1STomasz Miąsko 686cc6ada1STomasz Miąsko enum class LeaveGenericsOpen { 696cc6ada1STomasz Miąsko No, 706cc6ada1STomasz Miąsko Yes, 716cc6ada1STomasz Miąsko }; 726cc6ada1STomasz Miąsko 736cc6ada1STomasz Miąsko class Demangler { 746cc6ada1STomasz Miąsko // Maximum recursion level. Used to avoid stack overflow. 756cc6ada1STomasz Miąsko size_t MaxRecursionLevel; 766cc6ada1STomasz Miąsko // Current recursion level. 776cc6ada1STomasz Miąsko size_t RecursionLevel; 786cc6ada1STomasz Miąsko size_t BoundLifetimes; 796cc6ada1STomasz Miąsko // Input string that is being demangled with "_R" prefix removed. 806cc6ada1STomasz Miąsko StringView Input; 816cc6ada1STomasz Miąsko // Position in the input string. 826cc6ada1STomasz Miąsko size_t Position; 836cc6ada1STomasz Miąsko // When true, print methods append the output to the stream. 846cc6ada1STomasz Miąsko // When false, the output is suppressed. 856cc6ada1STomasz Miąsko bool Print; 866cc6ada1STomasz Miąsko // True if an error occurred. 876cc6ada1STomasz Miąsko bool Error; 886cc6ada1STomasz Miąsko 896cc6ada1STomasz Miąsko public: 906cc6ada1STomasz Miąsko // Demangled output. 91*2e97236aSLuís Ferreira OutputBuffer Output; 926cc6ada1STomasz Miąsko 936cc6ada1STomasz Miąsko Demangler(size_t MaxRecursionLevel = 500); 946cc6ada1STomasz Miąsko 956cc6ada1STomasz Miąsko bool demangle(StringView MangledName); 966cc6ada1STomasz Miąsko 976cc6ada1STomasz Miąsko private: 986cc6ada1STomasz Miąsko bool demanglePath(IsInType Type, 996cc6ada1STomasz Miąsko LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No); 1006cc6ada1STomasz Miąsko void demangleImplPath(IsInType InType); 1016cc6ada1STomasz Miąsko void demangleGenericArg(); 1026cc6ada1STomasz Miąsko void demangleType(); 1036cc6ada1STomasz Miąsko void demangleFnSig(); 1046cc6ada1STomasz Miąsko void demangleDynBounds(); 1056cc6ada1STomasz Miąsko void demangleDynTrait(); 1066cc6ada1STomasz Miąsko void demangleOptionalBinder(); 1076cc6ada1STomasz Miąsko void demangleConst(); 1086cc6ada1STomasz Miąsko void demangleConstInt(); 1096cc6ada1STomasz Miąsko void demangleConstBool(); 1106cc6ada1STomasz Miąsko void demangleConstChar(); 1116cc6ada1STomasz Miąsko 1126cc6ada1STomasz Miąsko template <typename Callable> void demangleBackref(Callable Demangler) { 1136cc6ada1STomasz Miąsko uint64_t Backref = parseBase62Number(); 1146cc6ada1STomasz Miąsko if (Error || Backref >= Position) { 1156cc6ada1STomasz Miąsko Error = true; 1166cc6ada1STomasz Miąsko return; 1176cc6ada1STomasz Miąsko } 1186cc6ada1STomasz Miąsko 1196cc6ada1STomasz Miąsko if (!Print) 1206cc6ada1STomasz Miąsko return; 1216cc6ada1STomasz Miąsko 1226cc6ada1STomasz Miąsko SwapAndRestore<size_t> SavePosition(Position, Position); 1236cc6ada1STomasz Miąsko Position = Backref; 1246cc6ada1STomasz Miąsko Demangler(); 1256cc6ada1STomasz Miąsko } 1266cc6ada1STomasz Miąsko 1276cc6ada1STomasz Miąsko Identifier parseIdentifier(); 1286cc6ada1STomasz Miąsko uint64_t parseOptionalBase62Number(char Tag); 1296cc6ada1STomasz Miąsko uint64_t parseBase62Number(); 1306cc6ada1STomasz Miąsko uint64_t parseDecimalNumber(); 1316cc6ada1STomasz Miąsko uint64_t parseHexNumber(StringView &HexDigits); 1326cc6ada1STomasz Miąsko 1336cc6ada1STomasz Miąsko void print(char C); 1346cc6ada1STomasz Miąsko void print(StringView S); 1356cc6ada1STomasz Miąsko void printDecimalNumber(uint64_t N); 1366cc6ada1STomasz Miąsko void printBasicType(BasicType); 1376cc6ada1STomasz Miąsko void printLifetime(uint64_t Index); 138c8c2b462STomasz Miąsko void printIdentifier(Identifier Ident); 1396cc6ada1STomasz Miąsko 1406cc6ada1STomasz Miąsko char look() const; 1416cc6ada1STomasz Miąsko char consume(); 1426cc6ada1STomasz Miąsko bool consumeIf(char Prefix); 1436cc6ada1STomasz Miąsko 1446cc6ada1STomasz Miąsko bool addAssign(uint64_t &A, uint64_t B); 1456cc6ada1STomasz Miąsko bool mulAssign(uint64_t &A, uint64_t B); 1466cc6ada1STomasz Miąsko }; 1476cc6ada1STomasz Miąsko 1486cc6ada1STomasz Miąsko } // namespace 1497310403eSTomasz Miąsko 1507310403eSTomasz Miąsko char *llvm::rustDemangle(const char *MangledName, char *Buf, size_t *N, 1517310403eSTomasz Miąsko int *Status) { 1527310403eSTomasz Miąsko if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { 1537310403eSTomasz Miąsko if (Status != nullptr) 1547310403eSTomasz Miąsko *Status = demangle_invalid_args; 1557310403eSTomasz Miąsko return nullptr; 1567310403eSTomasz Miąsko } 1577310403eSTomasz Miąsko 1587310403eSTomasz Miąsko // Return early if mangled name doesn't look like a Rust symbol. 1597310403eSTomasz Miąsko StringView Mangled(MangledName); 1607310403eSTomasz Miąsko if (!Mangled.startsWith("_R")) { 1617310403eSTomasz Miąsko if (Status != nullptr) 1627310403eSTomasz Miąsko *Status = demangle_invalid_mangled_name; 1637310403eSTomasz Miąsko return nullptr; 1647310403eSTomasz Miąsko } 1657310403eSTomasz Miąsko 1667310403eSTomasz Miąsko Demangler D; 167*2e97236aSLuís Ferreira if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024)) { 1687310403eSTomasz Miąsko if (Status != nullptr) 1697310403eSTomasz Miąsko *Status = demangle_memory_alloc_failure; 1707310403eSTomasz Miąsko return nullptr; 1717310403eSTomasz Miąsko } 1727310403eSTomasz Miąsko 1737310403eSTomasz Miąsko if (!D.demangle(Mangled)) { 1747310403eSTomasz Miąsko if (Status != nullptr) 1757310403eSTomasz Miąsko *Status = demangle_invalid_mangled_name; 1767310403eSTomasz Miąsko std::free(D.Output.getBuffer()); 1777310403eSTomasz Miąsko return nullptr; 1787310403eSTomasz Miąsko } 1797310403eSTomasz Miąsko 1807310403eSTomasz Miąsko D.Output += '\0'; 1817310403eSTomasz Miąsko char *Demangled = D.Output.getBuffer(); 1827310403eSTomasz Miąsko size_t DemangledLen = D.Output.getCurrentPosition(); 1837310403eSTomasz Miąsko 1847310403eSTomasz Miąsko if (Buf != nullptr) { 1857310403eSTomasz Miąsko if (DemangledLen <= *N) { 1867310403eSTomasz Miąsko std::memcpy(Buf, Demangled, DemangledLen); 1877310403eSTomasz Miąsko std::free(Demangled); 1887310403eSTomasz Miąsko Demangled = Buf; 1897310403eSTomasz Miąsko } else { 1907310403eSTomasz Miąsko std::free(Buf); 1917310403eSTomasz Miąsko } 1927310403eSTomasz Miąsko } 1937310403eSTomasz Miąsko 1947310403eSTomasz Miąsko if (N != nullptr) 1957310403eSTomasz Miąsko *N = DemangledLen; 1967310403eSTomasz Miąsko 1977310403eSTomasz Miąsko if (Status != nullptr) 1987310403eSTomasz Miąsko *Status = demangle_success; 1997310403eSTomasz Miąsko 2007310403eSTomasz Miąsko return Demangled; 2017310403eSTomasz Miąsko } 2027310403eSTomasz Miąsko 2037310403eSTomasz Miąsko Demangler::Demangler(size_t MaxRecursionLevel) 2047310403eSTomasz Miąsko : MaxRecursionLevel(MaxRecursionLevel) {} 2057310403eSTomasz Miąsko 2067310403eSTomasz Miąsko static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; } 2077310403eSTomasz Miąsko 208cd74dd17STomasz Miąsko static inline bool isHexDigit(const char C) { 209cd74dd17STomasz Miąsko return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f'); 210cd74dd17STomasz Miąsko } 211cd74dd17STomasz Miąsko 2127310403eSTomasz Miąsko static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; } 2137310403eSTomasz Miąsko 2147310403eSTomasz Miąsko static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; } 2157310403eSTomasz Miąsko 2167310403eSTomasz Miąsko /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. 2177310403eSTomasz Miąsko static inline bool isValid(const char C) { 2187310403eSTomasz Miąsko return isDigit(C) || isLower(C) || isUpper(C) || C == '_'; 2197310403eSTomasz Miąsko } 2207310403eSTomasz Miąsko 2217310403eSTomasz Miąsko // Demangles Rust v0 mangled symbol. Returns true when successful, and false 2227310403eSTomasz Miąsko // otherwise. The demangled symbol is stored in Output field. It is 2237310403eSTomasz Miąsko // responsibility of the caller to free the memory behind the output stream. 2247310403eSTomasz Miąsko // 2257310403eSTomasz Miąsko // <symbol-name> = "_R" <path> [<instantiating-crate>] 2267310403eSTomasz Miąsko bool Demangler::demangle(StringView Mangled) { 2277310403eSTomasz Miąsko Position = 0; 2287310403eSTomasz Miąsko Error = false; 229f0f2a8b2STomasz Miąsko Print = true; 2307310403eSTomasz Miąsko RecursionLevel = 0; 231a67a234eSTomasz Miąsko BoundLifetimes = 0; 2327310403eSTomasz Miąsko 2337310403eSTomasz Miąsko if (!Mangled.consumeFront("_R")) { 2347310403eSTomasz Miąsko Error = true; 2357310403eSTomasz Miąsko return false; 2367310403eSTomasz Miąsko } 2372a5bb9c8STomasz Miąsko size_t Dot = Mangled.find('.'); 2382a5bb9c8STomasz Miąsko Input = Mangled.substr(0, Dot); 2392a5bb9c8STomasz Miąsko StringView Suffix = Mangled.dropFront(Dot); 2407310403eSTomasz Miąsko 2416cc6ada1STomasz Miąsko demanglePath(IsInType::No); 2427310403eSTomasz Miąsko 24343929cccSTomasz Miąsko if (Position != Input.size()) { 24443929cccSTomasz Miąsko SwapAndRestore<bool> SavePrint(Print, false); 2456cc6ada1STomasz Miąsko demanglePath(IsInType::No); 24643929cccSTomasz Miąsko } 2477310403eSTomasz Miąsko 2487310403eSTomasz Miąsko if (Position != Input.size()) 2497310403eSTomasz Miąsko Error = true; 2507310403eSTomasz Miąsko 2512a5bb9c8STomasz Miąsko if (!Suffix.empty()) { 2522a5bb9c8STomasz Miąsko print(" ("); 2532a5bb9c8STomasz Miąsko print(Suffix); 2542a5bb9c8STomasz Miąsko print(")"); 2552a5bb9c8STomasz Miąsko } 2562a5bb9c8STomasz Miąsko 2577310403eSTomasz Miąsko return !Error; 2587310403eSTomasz Miąsko } 2597310403eSTomasz Miąsko 260619a65e5STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type. When 261619a65e5STomasz Miąsko // LeaveOpen is true, a closing `>` after generic arguments is omitted from the 262619a65e5STomasz Miąsko // output. Return value indicates whether generics arguments have been left 263619a65e5STomasz Miąsko // open. 26406833297STomasz Miąsko // 2657310403eSTomasz Miąsko // <path> = "C" <identifier> // crate root 2667310403eSTomasz Miąsko // | "M" <impl-path> <type> // <T> (inherent impl) 2677310403eSTomasz Miąsko // | "X" <impl-path> <type> <path> // <T as Trait> (trait impl) 2687310403eSTomasz Miąsko // | "Y" <type> <path> // <T as Trait> (trait definition) 2697310403eSTomasz Miąsko // | "N" <ns> <path> <identifier> // ...::ident (nested path) 2707310403eSTomasz Miąsko // | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args) 2717310403eSTomasz Miąsko // | <backref> 2727310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier> 2737310403eSTomasz Miąsko // <ns> = "C" // closure 2747310403eSTomasz Miąsko // | "S" // shim 2757310403eSTomasz Miąsko // | <A-Z> // other special namespaces 2767310403eSTomasz Miąsko // | <a-z> // internal namespaces 2776cc6ada1STomasz Miąsko bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { 2787310403eSTomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 2797310403eSTomasz Miąsko Error = true; 280619a65e5STomasz Miąsko return false; 2817310403eSTomasz Miąsko } 28278e94915STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 2837310403eSTomasz Miąsko 2847310403eSTomasz Miąsko switch (consume()) { 2857310403eSTomasz Miąsko case 'C': { 2867310403eSTomasz Miąsko parseOptionalBase62Number('s'); 287c8c2b462STomasz Miąsko printIdentifier(parseIdentifier()); 2887310403eSTomasz Miąsko break; 2897310403eSTomasz Miąsko } 290f0f2a8b2STomasz Miąsko case 'M': { 29106833297STomasz Miąsko demangleImplPath(InType); 292f0f2a8b2STomasz Miąsko print("<"); 293f0f2a8b2STomasz Miąsko demangleType(); 294f0f2a8b2STomasz Miąsko print(">"); 295f0f2a8b2STomasz Miąsko break; 296f0f2a8b2STomasz Miąsko } 2979fa13800STomasz Miąsko case 'X': { 29806833297STomasz Miąsko demangleImplPath(InType); 2999fa13800STomasz Miąsko print("<"); 3009fa13800STomasz Miąsko demangleType(); 3019fa13800STomasz Miąsko print(" as "); 3026cc6ada1STomasz Miąsko demanglePath(IsInType::Yes); 3039fa13800STomasz Miąsko print(">"); 3049fa13800STomasz Miąsko break; 3059fa13800STomasz Miąsko } 306f933f7fbSTomasz Miąsko case 'Y': { 307f933f7fbSTomasz Miąsko print("<"); 308f933f7fbSTomasz Miąsko demangleType(); 309f933f7fbSTomasz Miąsko print(" as "); 3106cc6ada1STomasz Miąsko demanglePath(IsInType::Yes); 311f933f7fbSTomasz Miąsko print(">"); 312f933f7fbSTomasz Miąsko break; 313f933f7fbSTomasz Miąsko } 3147310403eSTomasz Miąsko case 'N': { 3157310403eSTomasz Miąsko char NS = consume(); 3167310403eSTomasz Miąsko if (!isLower(NS) && !isUpper(NS)) { 3177310403eSTomasz Miąsko Error = true; 3187310403eSTomasz Miąsko break; 3197310403eSTomasz Miąsko } 32006833297STomasz Miąsko demanglePath(InType); 3217310403eSTomasz Miąsko 32278e94915STomasz Miąsko uint64_t Disambiguator = parseOptionalBase62Number('s'); 3237310403eSTomasz Miąsko Identifier Ident = parseIdentifier(); 3247310403eSTomasz Miąsko 32578e94915STomasz Miąsko if (isUpper(NS)) { 32678e94915STomasz Miąsko // Special namespaces 32778e94915STomasz Miąsko print("::{"); 32878e94915STomasz Miąsko if (NS == 'C') 32978e94915STomasz Miąsko print("closure"); 33078e94915STomasz Miąsko else if (NS == 'S') 33178e94915STomasz Miąsko print("shim"); 33278e94915STomasz Miąsko else 33378e94915STomasz Miąsko print(NS); 3347310403eSTomasz Miąsko if (!Ident.empty()) { 33578e94915STomasz Miąsko print(":"); 336c8c2b462STomasz Miąsko printIdentifier(Ident); 33778e94915STomasz Miąsko } 33878e94915STomasz Miąsko print('#'); 33978e94915STomasz Miąsko printDecimalNumber(Disambiguator); 34078e94915STomasz Miąsko print('}'); 34178e94915STomasz Miąsko } else { 34278e94915STomasz Miąsko // Implementation internal namespaces. 34378e94915STomasz Miąsko if (!Ident.empty()) { 3447310403eSTomasz Miąsko print("::"); 345c8c2b462STomasz Miąsko printIdentifier(Ident); 3467310403eSTomasz Miąsko } 34778e94915STomasz Miąsko } 3487310403eSTomasz Miąsko break; 3497310403eSTomasz Miąsko } 3502961f863STomasz Miąsko case 'I': { 35106833297STomasz Miąsko demanglePath(InType); 35206833297STomasz Miąsko // Omit "::" when in a type, where it is optional. 3536cc6ada1STomasz Miąsko if (InType == IsInType::No) 35406833297STomasz Miąsko print("::"); 35506833297STomasz Miąsko print("<"); 3562961f863STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 3572961f863STomasz Miąsko if (I > 0) 3582961f863STomasz Miąsko print(", "); 3592961f863STomasz Miąsko demangleGenericArg(); 3602961f863STomasz Miąsko } 3616cc6ada1STomasz Miąsko if (LeaveOpen == LeaveGenericsOpen::Yes) 362619a65e5STomasz Miąsko return true; 363619a65e5STomasz Miąsko else 3642961f863STomasz Miąsko print(">"); 3652961f863STomasz Miąsko break; 3662961f863STomasz Miąsko } 36782b7e822STomasz Miąsko case 'B': { 36882b7e822STomasz Miąsko bool IsOpen = false; 36982b7e822STomasz Miąsko demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); }); 37082b7e822STomasz Miąsko return IsOpen; 37182b7e822STomasz Miąsko } 3727310403eSTomasz Miąsko default: 3737310403eSTomasz Miąsko Error = true; 3747310403eSTomasz Miąsko break; 3757310403eSTomasz Miąsko } 376619a65e5STomasz Miąsko 377619a65e5STomasz Miąsko return false; 3787310403eSTomasz Miąsko } 3797310403eSTomasz Miąsko 380f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path> 381f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number> 3826cc6ada1STomasz Miąsko void Demangler::demangleImplPath(IsInType InType) { 383f0f2a8b2STomasz Miąsko SwapAndRestore<bool> SavePrint(Print, false); 384f0f2a8b2STomasz Miąsko parseOptionalBase62Number('s'); 38506833297STomasz Miąsko demanglePath(InType); 386f0f2a8b2STomasz Miąsko } 387f0f2a8b2STomasz Miąsko 3882961f863STomasz Miąsko // <generic-arg> = <lifetime> 3892961f863STomasz Miąsko // | <type> 3902961f863STomasz Miąsko // | "K" <const> 3912961f863STomasz Miąsko // <lifetime> = "L" <base-62-number> 3922961f863STomasz Miąsko void Demangler::demangleGenericArg() { 393a67a234eSTomasz Miąsko if (consumeIf('L')) 394a67a234eSTomasz Miąsko printLifetime(parseBase62Number()); 395a67a234eSTomasz Miąsko else if (consumeIf('K')) 396cd74dd17STomasz Miąsko demangleConst(); 397cd74dd17STomasz Miąsko else 3982961f863STomasz Miąsko demangleType(); 3992961f863STomasz Miąsko } 4002961f863STomasz Miąsko 4012961f863STomasz Miąsko // <basic-type> = "a" // i8 4022961f863STomasz Miąsko // | "b" // bool 4032961f863STomasz Miąsko // | "c" // char 4042961f863STomasz Miąsko // | "d" // f64 4052961f863STomasz Miąsko // | "e" // str 4062961f863STomasz Miąsko // | "f" // f32 4072961f863STomasz Miąsko // | "h" // u8 4082961f863STomasz Miąsko // | "i" // isize 4092961f863STomasz Miąsko // | "j" // usize 4102961f863STomasz Miąsko // | "l" // i32 4112961f863STomasz Miąsko // | "m" // u32 4122961f863STomasz Miąsko // | "n" // i128 4132961f863STomasz Miąsko // | "o" // u128 4142961f863STomasz Miąsko // | "s" // i16 4152961f863STomasz Miąsko // | "t" // u16 4162961f863STomasz Miąsko // | "u" // () 4172961f863STomasz Miąsko // | "v" // ... 4182961f863STomasz Miąsko // | "x" // i64 4192961f863STomasz Miąsko // | "y" // u64 4202961f863STomasz Miąsko // | "z" // ! 4212961f863STomasz Miąsko // | "p" // placeholder (e.g. for generic params), shown as _ 422cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) { 423cd74dd17STomasz Miąsko switch (C) { 424cd74dd17STomasz Miąsko case 'a': 425cd74dd17STomasz Miąsko Type = BasicType::I8; 426cd74dd17STomasz Miąsko return true; 427cd74dd17STomasz Miąsko case 'b': 428cd74dd17STomasz Miąsko Type = BasicType::Bool; 429cd74dd17STomasz Miąsko return true; 430cd74dd17STomasz Miąsko case 'c': 431cd74dd17STomasz Miąsko Type = BasicType::Char; 432cd74dd17STomasz Miąsko return true; 433cd74dd17STomasz Miąsko case 'd': 434cd74dd17STomasz Miąsko Type = BasicType::F64; 435cd74dd17STomasz Miąsko return true; 436cd74dd17STomasz Miąsko case 'e': 437cd74dd17STomasz Miąsko Type = BasicType::Str; 438cd74dd17STomasz Miąsko return true; 439cd74dd17STomasz Miąsko case 'f': 440cd74dd17STomasz Miąsko Type = BasicType::F32; 441cd74dd17STomasz Miąsko return true; 442cd74dd17STomasz Miąsko case 'h': 443cd74dd17STomasz Miąsko Type = BasicType::U8; 444cd74dd17STomasz Miąsko return true; 445cd74dd17STomasz Miąsko case 'i': 446cd74dd17STomasz Miąsko Type = BasicType::ISize; 447cd74dd17STomasz Miąsko return true; 448cd74dd17STomasz Miąsko case 'j': 449cd74dd17STomasz Miąsko Type = BasicType::USize; 450cd74dd17STomasz Miąsko return true; 451cd74dd17STomasz Miąsko case 'l': 452cd74dd17STomasz Miąsko Type = BasicType::I32; 453cd74dd17STomasz Miąsko return true; 454cd74dd17STomasz Miąsko case 'm': 455cd74dd17STomasz Miąsko Type = BasicType::U32; 456cd74dd17STomasz Miąsko return true; 457cd74dd17STomasz Miąsko case 'n': 458cd74dd17STomasz Miąsko Type = BasicType::I128; 459cd74dd17STomasz Miąsko return true; 460cd74dd17STomasz Miąsko case 'o': 461cd74dd17STomasz Miąsko Type = BasicType::U128; 462cd74dd17STomasz Miąsko return true; 463cd74dd17STomasz Miąsko case 'p': 464cd74dd17STomasz Miąsko Type = BasicType::Placeholder; 465cd74dd17STomasz Miąsko return true; 466cd74dd17STomasz Miąsko case 's': 467cd74dd17STomasz Miąsko Type = BasicType::I16; 468cd74dd17STomasz Miąsko return true; 469cd74dd17STomasz Miąsko case 't': 470cd74dd17STomasz Miąsko Type = BasicType::U16; 471cd74dd17STomasz Miąsko return true; 472cd74dd17STomasz Miąsko case 'u': 473cd74dd17STomasz Miąsko Type = BasicType::Unit; 474cd74dd17STomasz Miąsko return true; 475cd74dd17STomasz Miąsko case 'v': 476cd74dd17STomasz Miąsko Type = BasicType::Variadic; 477cd74dd17STomasz Miąsko return true; 478cd74dd17STomasz Miąsko case 'x': 479cd74dd17STomasz Miąsko Type = BasicType::I64; 480cd74dd17STomasz Miąsko return true; 481cd74dd17STomasz Miąsko case 'y': 482cd74dd17STomasz Miąsko Type = BasicType::U64; 483cd74dd17STomasz Miąsko return true; 484cd74dd17STomasz Miąsko case 'z': 485cd74dd17STomasz Miąsko Type = BasicType::Never; 486cd74dd17STomasz Miąsko return true; 487cd74dd17STomasz Miąsko default: 488cd74dd17STomasz Miąsko return false; 489cd74dd17STomasz Miąsko } 490cd74dd17STomasz Miąsko } 491cd74dd17STomasz Miąsko 492cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) { 493cd74dd17STomasz Miąsko switch (Type) { 494cd74dd17STomasz Miąsko case BasicType::Bool: 495cd74dd17STomasz Miąsko print("bool"); 496cd74dd17STomasz Miąsko break; 497cd74dd17STomasz Miąsko case BasicType::Char: 498cd74dd17STomasz Miąsko print("char"); 499cd74dd17STomasz Miąsko break; 500cd74dd17STomasz Miąsko case BasicType::I8: 501cd74dd17STomasz Miąsko print("i8"); 502cd74dd17STomasz Miąsko break; 503cd74dd17STomasz Miąsko case BasicType::I16: 504cd74dd17STomasz Miąsko print("i16"); 505cd74dd17STomasz Miąsko break; 506cd74dd17STomasz Miąsko case BasicType::I32: 507cd74dd17STomasz Miąsko print("i32"); 508cd74dd17STomasz Miąsko break; 509cd74dd17STomasz Miąsko case BasicType::I64: 510cd74dd17STomasz Miąsko print("i64"); 511cd74dd17STomasz Miąsko break; 512cd74dd17STomasz Miąsko case BasicType::I128: 513cd74dd17STomasz Miąsko print("i128"); 514cd74dd17STomasz Miąsko break; 515cd74dd17STomasz Miąsko case BasicType::ISize: 516cd74dd17STomasz Miąsko print("isize"); 517cd74dd17STomasz Miąsko break; 518cd74dd17STomasz Miąsko case BasicType::U8: 519cd74dd17STomasz Miąsko print("u8"); 520cd74dd17STomasz Miąsko break; 521cd74dd17STomasz Miąsko case BasicType::U16: 522cd74dd17STomasz Miąsko print("u16"); 523cd74dd17STomasz Miąsko break; 524cd74dd17STomasz Miąsko case BasicType::U32: 525cd74dd17STomasz Miąsko print("u32"); 526cd74dd17STomasz Miąsko break; 527cd74dd17STomasz Miąsko case BasicType::U64: 528cd74dd17STomasz Miąsko print("u64"); 529cd74dd17STomasz Miąsko break; 530cd74dd17STomasz Miąsko case BasicType::U128: 531cd74dd17STomasz Miąsko print("u128"); 532cd74dd17STomasz Miąsko break; 533cd74dd17STomasz Miąsko case BasicType::USize: 534cd74dd17STomasz Miąsko print("usize"); 535cd74dd17STomasz Miąsko break; 536cd74dd17STomasz Miąsko case BasicType::F32: 537cd74dd17STomasz Miąsko print("f32"); 538cd74dd17STomasz Miąsko break; 539cd74dd17STomasz Miąsko case BasicType::F64: 540cd74dd17STomasz Miąsko print("f64"); 541cd74dd17STomasz Miąsko break; 542cd74dd17STomasz Miąsko case BasicType::Str: 543cd74dd17STomasz Miąsko print("str"); 544cd74dd17STomasz Miąsko break; 545cd74dd17STomasz Miąsko case BasicType::Placeholder: 546cd74dd17STomasz Miąsko print("_"); 547cd74dd17STomasz Miąsko break; 548cd74dd17STomasz Miąsko case BasicType::Unit: 549cd74dd17STomasz Miąsko print("()"); 550cd74dd17STomasz Miąsko break; 551cd74dd17STomasz Miąsko case BasicType::Variadic: 552cd74dd17STomasz Miąsko print("..."); 553cd74dd17STomasz Miąsko break; 554cd74dd17STomasz Miąsko case BasicType::Never: 555cd74dd17STomasz Miąsko print("!"); 556cd74dd17STomasz Miąsko break; 557cd74dd17STomasz Miąsko } 5582961f863STomasz Miąsko } 5592961f863STomasz Miąsko 5602961f863STomasz Miąsko // <type> = | <basic-type> 5612961f863STomasz Miąsko // | <path> // named type 5622961f863STomasz Miąsko // | "A" <type> <const> // [T; N] 5632961f863STomasz Miąsko // | "S" <type> // [T] 5642961f863STomasz Miąsko // | "T" {<type>} "E" // (T1, T2, T3, ...) 5652961f863STomasz Miąsko // | "R" [<lifetime>] <type> // &T 5662961f863STomasz Miąsko // | "Q" [<lifetime>] <type> // &mut T 5672961f863STomasz Miąsko // | "P" <type> // *const T 5682961f863STomasz Miąsko // | "O" <type> // *mut T 5692961f863STomasz Miąsko // | "F" <fn-sig> // fn(...) -> ... 5702961f863STomasz Miąsko // | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a 5712961f863STomasz Miąsko // | <backref> // backref 5722961f863STomasz Miąsko void Demangler::demangleType() { 57344d63c57STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 57444d63c57STomasz Miąsko Error = true; 57544d63c57STomasz Miąsko return; 57644d63c57STomasz Miąsko } 57744d63c57STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 57806833297STomasz Miąsko 57944d63c57STomasz Miąsko size_t Start = Position; 580b42400ccSTomasz Miąsko char C = consume(); 581b42400ccSTomasz Miąsko BasicType Type; 582b42400ccSTomasz Miąsko if (parseBasicType(C, Type)) 583b42400ccSTomasz Miąsko return printBasicType(Type); 584b42400ccSTomasz Miąsko 585b42400ccSTomasz Miąsko switch (C) { 586b42400ccSTomasz Miąsko case 'A': 587b42400ccSTomasz Miąsko print("["); 588b42400ccSTomasz Miąsko demangleType(); 589b42400ccSTomasz Miąsko print("; "); 590b42400ccSTomasz Miąsko demangleConst(); 591b42400ccSTomasz Miąsko print("]"); 592b42400ccSTomasz Miąsko break; 593a84c65c2STomasz Miąsko case 'S': 594a84c65c2STomasz Miąsko print("["); 595a84c65c2STomasz Miąsko demangleType(); 596a84c65c2STomasz Miąsko print("]"); 597a84c65c2STomasz Miąsko break; 598774de7a0STomasz Miąsko case 'T': { 599774de7a0STomasz Miąsko print("("); 600774de7a0STomasz Miąsko size_t I = 0; 601774de7a0STomasz Miąsko for (; !Error && !consumeIf('E'); ++I) { 602774de7a0STomasz Miąsko if (I > 0) 603774de7a0STomasz Miąsko print(", "); 604774de7a0STomasz Miąsko demangleType(); 605774de7a0STomasz Miąsko } 606774de7a0STomasz Miąsko if (I == 1) 607774de7a0STomasz Miąsko print(","); 608774de7a0STomasz Miąsko print(")"); 609774de7a0STomasz Miąsko break; 610774de7a0STomasz Miąsko } 611e4fa6c95STomasz Miąsko case 'R': 612e4fa6c95STomasz Miąsko case 'Q': 613a67a234eSTomasz Miąsko print('&'); 614a67a234eSTomasz Miąsko if (consumeIf('L')) { 615a67a234eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) { 616a67a234eSTomasz Miąsko printLifetime(Lifetime); 617a67a234eSTomasz Miąsko print(' '); 618a67a234eSTomasz Miąsko } 619a67a234eSTomasz Miąsko } 620a67a234eSTomasz Miąsko if (C == 'Q') 621a67a234eSTomasz Miąsko print("mut "); 622e4fa6c95STomasz Miąsko demangleType(); 623e4fa6c95STomasz Miąsko break; 6246aac5633STomasz Miąsko case 'P': 6256aac5633STomasz Miąsko print("*const "); 6266aac5633STomasz Miąsko demangleType(); 6276aac5633STomasz Miąsko break; 6286aac5633STomasz Miąsko case 'O': 6296aac5633STomasz Miąsko print("*mut "); 6306aac5633STomasz Miąsko demangleType(); 6316aac5633STomasz Miąsko break; 63275cc1cf0STomasz Miąsko case 'F': 63375cc1cf0STomasz Miąsko demangleFnSig(); 63475cc1cf0STomasz Miąsko break; 63589615a5eSTomasz Miąsko case 'D': 63689615a5eSTomasz Miąsko demangleDynBounds(); 63789615a5eSTomasz Miąsko if (consumeIf('L')) { 63889615a5eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) { 63989615a5eSTomasz Miąsko print(" + "); 64089615a5eSTomasz Miąsko printLifetime(Lifetime); 64189615a5eSTomasz Miąsko } 64289615a5eSTomasz Miąsko } else { 64389615a5eSTomasz Miąsko Error = true; 64489615a5eSTomasz Miąsko } 64589615a5eSTomasz Miąsko break; 64644d63c57STomasz Miąsko case 'B': 64744d63c57STomasz Miąsko demangleBackref([&] { demangleType(); }); 64844d63c57STomasz Miąsko break; 649b42400ccSTomasz Miąsko default: 650b42400ccSTomasz Miąsko Position = Start; 6516cc6ada1STomasz Miąsko demanglePath(IsInType::Yes); 652b42400ccSTomasz Miąsko break; 653b42400ccSTomasz Miąsko } 654cd74dd17STomasz Miąsko } 655cd74dd17STomasz Miąsko 65675cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type> 65775cc1cf0STomasz Miąsko // <abi> = "C" 65875cc1cf0STomasz Miąsko // | <undisambiguated-identifier> 65975cc1cf0STomasz Miąsko void Demangler::demangleFnSig() { 660a67a234eSTomasz Miąsko SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 661a67a234eSTomasz Miąsko demangleOptionalBinder(); 66275cc1cf0STomasz Miąsko 66375cc1cf0STomasz Miąsko if (consumeIf('U')) 66475cc1cf0STomasz Miąsko print("unsafe "); 66575cc1cf0STomasz Miąsko 66675cc1cf0STomasz Miąsko if (consumeIf('K')) { 66775cc1cf0STomasz Miąsko print("extern \""); 66875cc1cf0STomasz Miąsko if (consumeIf('C')) { 66975cc1cf0STomasz Miąsko print("C"); 67075cc1cf0STomasz Miąsko } else { 67175cc1cf0STomasz Miąsko Identifier Ident = parseIdentifier(); 672c8c2b462STomasz Miąsko if (Ident.Punycode) 673c8c2b462STomasz Miąsko Error = true; 67475cc1cf0STomasz Miąsko for (char C : Ident.Name) { 67575cc1cf0STomasz Miąsko // When mangling ABI string, the "-" is replaced with "_". 67675cc1cf0STomasz Miąsko if (C == '_') 67775cc1cf0STomasz Miąsko C = '-'; 67875cc1cf0STomasz Miąsko print(C); 67975cc1cf0STomasz Miąsko } 68075cc1cf0STomasz Miąsko } 68175cc1cf0STomasz Miąsko print("\" "); 68275cc1cf0STomasz Miąsko } 68375cc1cf0STomasz Miąsko 68475cc1cf0STomasz Miąsko print("fn("); 68575cc1cf0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 68675cc1cf0STomasz Miąsko if (I > 0) 68775cc1cf0STomasz Miąsko print(", "); 68875cc1cf0STomasz Miąsko demangleType(); 68975cc1cf0STomasz Miąsko } 69075cc1cf0STomasz Miąsko print(")"); 69175cc1cf0STomasz Miąsko 69275cc1cf0STomasz Miąsko if (consumeIf('u')) { 69375cc1cf0STomasz Miąsko // Skip the unit type from the output. 69475cc1cf0STomasz Miąsko } else { 69575cc1cf0STomasz Miąsko print(" -> "); 69675cc1cf0STomasz Miąsko demangleType(); 69775cc1cf0STomasz Miąsko } 69875cc1cf0STomasz Miąsko } 69975cc1cf0STomasz Miąsko 70089615a5eSTomasz Miąsko // <dyn-bounds> = [<binder>] {<dyn-trait>} "E" 70189615a5eSTomasz Miąsko void Demangler::demangleDynBounds() { 70289615a5eSTomasz Miąsko SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes); 70389615a5eSTomasz Miąsko print("dyn "); 70489615a5eSTomasz Miąsko demangleOptionalBinder(); 7051499afa0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) { 7061499afa0STomasz Miąsko if (I > 0) 7071499afa0STomasz Miąsko print(" + "); 7081499afa0STomasz Miąsko demangleDynTrait(); 7091499afa0STomasz Miąsko } 7101499afa0STomasz Miąsko } 7111499afa0STomasz Miąsko 7121499afa0STomasz Miąsko // <dyn-trait> = <path> {<dyn-trait-assoc-binding>} 7131499afa0STomasz Miąsko // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type> 7141499afa0STomasz Miąsko void Demangler::demangleDynTrait() { 7156cc6ada1STomasz Miąsko bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes); 716619a65e5STomasz Miąsko while (!Error && consumeIf('p')) { 717619a65e5STomasz Miąsko if (!IsOpen) { 718619a65e5STomasz Miąsko IsOpen = true; 719619a65e5STomasz Miąsko print('<'); 720619a65e5STomasz Miąsko } else { 721619a65e5STomasz Miąsko print(", "); 722619a65e5STomasz Miąsko } 723619a65e5STomasz Miąsko print(parseIdentifier().Name); 724619a65e5STomasz Miąsko print(" = "); 725619a65e5STomasz Miąsko demangleType(); 726619a65e5STomasz Miąsko } 727619a65e5STomasz Miąsko if (IsOpen) 728619a65e5STomasz Miąsko print(">"); 72989615a5eSTomasz Miąsko } 73089615a5eSTomasz Miąsko 731a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes. 732a67a234eSTomasz Miąsko // 733a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number> 734a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() { 735a67a234eSTomasz Miąsko uint64_t Binder = parseOptionalBase62Number('G'); 736a67a234eSTomasz Miąsko if (Error || Binder == 0) 737a67a234eSTomasz Miąsko return; 738a67a234eSTomasz Miąsko 739a67a234eSTomasz Miąsko // In valid inputs each bound lifetime is referenced later. Referencing a 740a67a234eSTomasz Miąsko // lifetime requires at least one byte of input. Reject inputs that are too 741a67a234eSTomasz Miąsko // short to reference all bound lifetimes. Otherwise demangling of invalid 742a67a234eSTomasz Miąsko // binders could generate excessive amounts of output. 743a67a234eSTomasz Miąsko if (Binder >= Input.size() - BoundLifetimes) { 744a67a234eSTomasz Miąsko Error = true; 745a67a234eSTomasz Miąsko return; 746a67a234eSTomasz Miąsko } 747a67a234eSTomasz Miąsko 748a67a234eSTomasz Miąsko print("for<"); 749a67a234eSTomasz Miąsko for (size_t I = 0; I != Binder; ++I) { 750a67a234eSTomasz Miąsko BoundLifetimes += 1; 751a67a234eSTomasz Miąsko if (I > 0) 752a67a234eSTomasz Miąsko print(", "); 753a67a234eSTomasz Miąsko printLifetime(1); 754a67a234eSTomasz Miąsko } 755a67a234eSTomasz Miąsko print("> "); 756a67a234eSTomasz Miąsko } 757a67a234eSTomasz Miąsko 758cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data> 759cd74dd17STomasz Miąsko // | "p" // placeholder 760cd74dd17STomasz Miąsko // | <backref> 761cd74dd17STomasz Miąsko void Demangler::demangleConst() { 762f9a79356STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) { 763f9a79356STomasz Miąsko Error = true; 764f9a79356STomasz Miąsko return; 765f9a79356STomasz Miąsko } 766f9a79356STomasz Miąsko SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1); 767f9a79356STomasz Miąsko 768f9a79356STomasz Miąsko char C = consume(); 769cd74dd17STomasz Miąsko BasicType Type; 770f9a79356STomasz Miąsko if (parseBasicType(C, Type)) { 771cd74dd17STomasz Miąsko switch (Type) { 772cd74dd17STomasz Miąsko case BasicType::I8: 773cd74dd17STomasz Miąsko case BasicType::I16: 774cd74dd17STomasz Miąsko case BasicType::I32: 775cd74dd17STomasz Miąsko case BasicType::I64: 776cd74dd17STomasz Miąsko case BasicType::I128: 777cd74dd17STomasz Miąsko case BasicType::ISize: 778cd74dd17STomasz Miąsko case BasicType::U8: 779cd74dd17STomasz Miąsko case BasicType::U16: 780cd74dd17STomasz Miąsko case BasicType::U32: 781cd74dd17STomasz Miąsko case BasicType::U64: 782cd74dd17STomasz Miąsko case BasicType::U128: 783cd74dd17STomasz Miąsko case BasicType::USize: 784cd74dd17STomasz Miąsko demangleConstInt(); 785cd74dd17STomasz Miąsko break; 786fc0f2bb9STomasz Miąsko case BasicType::Bool: 787fc0f2bb9STomasz Miąsko demangleConstBool(); 788fc0f2bb9STomasz Miąsko break; 7892ba49f6aSTomasz Miąsko case BasicType::Char: 7902ba49f6aSTomasz Miąsko demangleConstChar(); 7912ba49f6aSTomasz Miąsko break; 792cd74dd17STomasz Miąsko case BasicType::Placeholder: 793cd74dd17STomasz Miąsko print('_'); 794cd74dd17STomasz Miąsko break; 795cd74dd17STomasz Miąsko default: 7962961f863STomasz Miąsko Error = true; 797cd74dd17STomasz Miąsko break; 798cd74dd17STomasz Miąsko } 799f9a79356STomasz Miąsko } else if (C == 'B') { 800f9a79356STomasz Miąsko demangleBackref([&] { demangleConst(); }); 801cd74dd17STomasz Miąsko } else { 802cd74dd17STomasz Miąsko Error = true; 803cd74dd17STomasz Miąsko } 804cd74dd17STomasz Miąsko } 805cd74dd17STomasz Miąsko 806cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number> 807cd74dd17STomasz Miąsko void Demangler::demangleConstInt() { 808cd74dd17STomasz Miąsko if (consumeIf('n')) 809cd74dd17STomasz Miąsko print('-'); 810cd74dd17STomasz Miąsko 811cd74dd17STomasz Miąsko StringView HexDigits; 812cd74dd17STomasz Miąsko uint64_t Value = parseHexNumber(HexDigits); 813cd74dd17STomasz Miąsko if (HexDigits.size() <= 16) { 814cd74dd17STomasz Miąsko printDecimalNumber(Value); 815cd74dd17STomasz Miąsko } else { 816cd74dd17STomasz Miąsko print("0x"); 817cd74dd17STomasz Miąsko print(HexDigits); 8182961f863STomasz Miąsko } 8192961f863STomasz Miąsko } 8202961f863STomasz Miąsko 821fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false 822fc0f2bb9STomasz Miąsko // | "1_" // true 823fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() { 824fc0f2bb9STomasz Miąsko StringView HexDigits; 825fc0f2bb9STomasz Miąsko parseHexNumber(HexDigits); 826fc0f2bb9STomasz Miąsko if (HexDigits == "0") 827fc0f2bb9STomasz Miąsko print("false"); 828fc0f2bb9STomasz Miąsko else if (HexDigits == "1") 829fc0f2bb9STomasz Miąsko print("true"); 830fc0f2bb9STomasz Miąsko else 831fc0f2bb9STomasz Miąsko Error = true; 832fc0f2bb9STomasz Miąsko } 833fc0f2bb9STomasz Miąsko 8342ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character. 8352ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) { 8362ba49f6aSTomasz Miąsko return 0x20 <= CodePoint && CodePoint <= 0x7e; 8372ba49f6aSTomasz Miąsko } 8382ba49f6aSTomasz Miąsko 8392ba49f6aSTomasz Miąsko // <const-data> = <hex-number> 8402ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() { 8412ba49f6aSTomasz Miąsko StringView HexDigits; 8422ba49f6aSTomasz Miąsko uint64_t CodePoint = parseHexNumber(HexDigits); 8432ba49f6aSTomasz Miąsko if (Error || HexDigits.size() > 6) { 8442ba49f6aSTomasz Miąsko Error = true; 8452ba49f6aSTomasz Miąsko return; 8462ba49f6aSTomasz Miąsko } 8472ba49f6aSTomasz Miąsko 8482ba49f6aSTomasz Miąsko print("'"); 8492ba49f6aSTomasz Miąsko switch (CodePoint) { 8502ba49f6aSTomasz Miąsko case '\t': 8512ba49f6aSTomasz Miąsko print(R"(\t)"); 8522ba49f6aSTomasz Miąsko break; 8532ba49f6aSTomasz Miąsko case '\r': 8542ba49f6aSTomasz Miąsko print(R"(\r)"); 8552ba49f6aSTomasz Miąsko break; 8562ba49f6aSTomasz Miąsko case '\n': 8572ba49f6aSTomasz Miąsko print(R"(\n)"); 8582ba49f6aSTomasz Miąsko break; 8592ba49f6aSTomasz Miąsko case '\\': 8602ba49f6aSTomasz Miąsko print(R"(\\)"); 8612ba49f6aSTomasz Miąsko break; 8622ba49f6aSTomasz Miąsko case '"': 8632ba49f6aSTomasz Miąsko print(R"(")"); 8642ba49f6aSTomasz Miąsko break; 8652ba49f6aSTomasz Miąsko case '\'': 8662ba49f6aSTomasz Miąsko print(R"(\')"); 8672ba49f6aSTomasz Miąsko break; 8682ba49f6aSTomasz Miąsko default: 8692ba49f6aSTomasz Miąsko if (isAsciiPrintable(CodePoint)) { 8702ba49f6aSTomasz Miąsko char C = CodePoint; 8712ba49f6aSTomasz Miąsko print(C); 8722ba49f6aSTomasz Miąsko } else { 8732ba49f6aSTomasz Miąsko print(R"(\u{)"); 8742ba49f6aSTomasz Miąsko print(HexDigits); 8752ba49f6aSTomasz Miąsko print('}'); 8762ba49f6aSTomasz Miąsko } 8772ba49f6aSTomasz Miąsko break; 8782ba49f6aSTomasz Miąsko } 8792ba49f6aSTomasz Miąsko print('\''); 8802ba49f6aSTomasz Miąsko } 8812ba49f6aSTomasz Miąsko 8827310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> 8837310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() { 8847310403eSTomasz Miąsko bool Punycode = consumeIf('u'); 8857310403eSTomasz Miąsko uint64_t Bytes = parseDecimalNumber(); 8867310403eSTomasz Miąsko 8877310403eSTomasz Miąsko // Underscore resolves the ambiguity when identifier starts with a decimal 8887310403eSTomasz Miąsko // digit or another underscore. 8897310403eSTomasz Miąsko consumeIf('_'); 8907310403eSTomasz Miąsko 8917310403eSTomasz Miąsko if (Error || Bytes > Input.size() - Position) { 8927310403eSTomasz Miąsko Error = true; 8937310403eSTomasz Miąsko return {}; 8947310403eSTomasz Miąsko } 8957310403eSTomasz Miąsko StringView S = Input.substr(Position, Bytes); 8967310403eSTomasz Miąsko Position += Bytes; 8977310403eSTomasz Miąsko 8987310403eSTomasz Miąsko if (!std::all_of(S.begin(), S.end(), isValid)) { 8997310403eSTomasz Miąsko Error = true; 9007310403eSTomasz Miąsko return {}; 9017310403eSTomasz Miąsko } 9027310403eSTomasz Miąsko 9037310403eSTomasz Miąsko return {S, Punycode}; 9047310403eSTomasz Miąsko } 9057310403eSTomasz Miąsko 9067310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using 907a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise 908a67a234eSTomasz Miąsko // 909a67a234eSTomasz Miąsko // This function is indended for parsing disambiguators and binders which when 910a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded 911a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is 912a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0. 91378e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) { 91478e94915STomasz Miąsko if (!consumeIf(Tag)) 91578e94915STomasz Miąsko return 0; 91678e94915STomasz Miąsko 91778e94915STomasz Miąsko uint64_t N = parseBase62Number(); 91878e94915STomasz Miąsko if (Error || !addAssign(N, 1)) 91978e94915STomasz Miąsko return 0; 92078e94915STomasz Miąsko 92178e94915STomasz Miąsko return N; 9227310403eSTomasz Miąsko } 9237310403eSTomasz Miąsko 9247310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by 9257310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, 9267310403eSTomasz Miąsko // "1_" encodes 2, etc. 9277310403eSTomasz Miąsko // 9287310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_" 9297310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() { 9307310403eSTomasz Miąsko if (consumeIf('_')) 9317310403eSTomasz Miąsko return 0; 9327310403eSTomasz Miąsko 9337310403eSTomasz Miąsko uint64_t Value = 0; 9347310403eSTomasz Miąsko 9357310403eSTomasz Miąsko while (true) { 9367310403eSTomasz Miąsko uint64_t Digit; 9377310403eSTomasz Miąsko char C = consume(); 9387310403eSTomasz Miąsko 9397310403eSTomasz Miąsko if (C == '_') { 9407310403eSTomasz Miąsko break; 9417310403eSTomasz Miąsko } else if (isDigit(C)) { 9427310403eSTomasz Miąsko Digit = C - '0'; 9437310403eSTomasz Miąsko } else if (isLower(C)) { 9447310403eSTomasz Miąsko Digit = 10 + (C - 'a'); 9457310403eSTomasz Miąsko } else if (isUpper(C)) { 9467310403eSTomasz Miąsko Digit = 10 + 26 + (C - 'A'); 9477310403eSTomasz Miąsko } else { 9487310403eSTomasz Miąsko Error = true; 9497310403eSTomasz Miąsko return 0; 9507310403eSTomasz Miąsko } 9517310403eSTomasz Miąsko 9527310403eSTomasz Miąsko if (!mulAssign(Value, 62)) 9537310403eSTomasz Miąsko return 0; 9547310403eSTomasz Miąsko 9557310403eSTomasz Miąsko if (!addAssign(Value, Digit)) 9567310403eSTomasz Miąsko return 0; 9577310403eSTomasz Miąsko } 9587310403eSTomasz Miąsko 9597310403eSTomasz Miąsko if (!addAssign(Value, 1)) 9607310403eSTomasz Miąsko return 0; 9617310403eSTomasz Miąsko 9627310403eSTomasz Miąsko return Value; 9637310403eSTomasz Miąsko } 9647310403eSTomasz Miąsko 9657310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros. 9667310403eSTomasz Miąsko // 9677310403eSTomasz Miąsko // <decimal-number> = "0" 9687310403eSTomasz Miąsko // | <1-9> {<0-9>} 9697310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() { 9707310403eSTomasz Miąsko char C = look(); 9717310403eSTomasz Miąsko if (!isDigit(C)) { 9727310403eSTomasz Miąsko Error = true; 9737310403eSTomasz Miąsko return 0; 9747310403eSTomasz Miąsko } 9757310403eSTomasz Miąsko 9767310403eSTomasz Miąsko if (C == '0') { 9777310403eSTomasz Miąsko consume(); 9787310403eSTomasz Miąsko return 0; 9797310403eSTomasz Miąsko } 9807310403eSTomasz Miąsko 9817310403eSTomasz Miąsko uint64_t Value = 0; 9827310403eSTomasz Miąsko 9837310403eSTomasz Miąsko while (isDigit(look())) { 9847310403eSTomasz Miąsko if (!mulAssign(Value, 10)) { 9857310403eSTomasz Miąsko Error = true; 9867310403eSTomasz Miąsko return 0; 9877310403eSTomasz Miąsko } 9887310403eSTomasz Miąsko 9897310403eSTomasz Miąsko uint64_t D = consume() - '0'; 9907310403eSTomasz Miąsko if (!addAssign(Value, D)) 9917310403eSTomasz Miąsko return 0; 9927310403eSTomasz Miąsko } 9937310403eSTomasz Miąsko 9947310403eSTomasz Miąsko return Value; 9957310403eSTomasz Miąsko } 996cd74dd17STomasz Miąsko 997cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed 998cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if 999cd74dd17STomasz Miąsko // HexDigits.size() > 16. 1000cd74dd17STomasz Miąsko // 1001cd74dd17STomasz Miąsko // <hex-number> = "0_" 1002cd74dd17STomasz Miąsko // | <1-9a-f> {<0-9a-f>} "_" 1003cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) { 1004cd74dd17STomasz Miąsko size_t Start = Position; 1005cd74dd17STomasz Miąsko uint64_t Value = 0; 1006cd74dd17STomasz Miąsko 1007cd74dd17STomasz Miąsko if (!isHexDigit(look())) 1008cd74dd17STomasz Miąsko Error = true; 1009cd74dd17STomasz Miąsko 1010cd74dd17STomasz Miąsko if (consumeIf('0')) { 1011cd74dd17STomasz Miąsko if (!consumeIf('_')) 1012cd74dd17STomasz Miąsko Error = true; 1013cd74dd17STomasz Miąsko } else { 1014cd74dd17STomasz Miąsko while (!Error && !consumeIf('_')) { 1015cd74dd17STomasz Miąsko char C = consume(); 1016cd74dd17STomasz Miąsko Value *= 16; 1017cd74dd17STomasz Miąsko if (isDigit(C)) 1018cd74dd17STomasz Miąsko Value += C - '0'; 1019cd74dd17STomasz Miąsko else if ('a' <= C && C <= 'f') 1020cd74dd17STomasz Miąsko Value += 10 + (C - 'a'); 1021cd74dd17STomasz Miąsko else 1022cd74dd17STomasz Miąsko Error = true; 1023cd74dd17STomasz Miąsko } 1024cd74dd17STomasz Miąsko } 1025cd74dd17STomasz Miąsko 1026cd74dd17STomasz Miąsko if (Error) { 1027cd74dd17STomasz Miąsko HexDigits = StringView(); 1028cd74dd17STomasz Miąsko return 0; 1029cd74dd17STomasz Miąsko } 1030cd74dd17STomasz Miąsko 1031cd74dd17STomasz Miąsko size_t End = Position - 1; 1032cd74dd17STomasz Miąsko assert(Start < End); 1033cd74dd17STomasz Miąsko HexDigits = Input.substr(Start, End - Start); 1034cd74dd17STomasz Miąsko return Value; 1035cd74dd17STomasz Miąsko } 1036a67a234eSTomasz Miąsko 10376cc6ada1STomasz Miąsko void Demangler::print(char C) { 10386cc6ada1STomasz Miąsko if (Error || !Print) 10396cc6ada1STomasz Miąsko return; 10406cc6ada1STomasz Miąsko 10416cc6ada1STomasz Miąsko Output += C; 10426cc6ada1STomasz Miąsko } 10436cc6ada1STomasz Miąsko 10446cc6ada1STomasz Miąsko void Demangler::print(StringView S) { 10456cc6ada1STomasz Miąsko if (Error || !Print) 10466cc6ada1STomasz Miąsko return; 10476cc6ada1STomasz Miąsko 10486cc6ada1STomasz Miąsko Output += S; 10496cc6ada1STomasz Miąsko } 10506cc6ada1STomasz Miąsko 10516cc6ada1STomasz Miąsko void Demangler::printDecimalNumber(uint64_t N) { 10526cc6ada1STomasz Miąsko if (Error || !Print) 10536cc6ada1STomasz Miąsko return; 10546cc6ada1STomasz Miąsko 10556cc6ada1STomasz Miąsko Output << N; 10566cc6ada1STomasz Miąsko } 10576cc6ada1STomasz Miąsko 1058a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices 1059a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes 1060a67a234eSTomasz Miąsko // bound by one of the enclosing binders. 1061a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) { 1062a67a234eSTomasz Miąsko if (Index == 0) { 1063a67a234eSTomasz Miąsko print("'_"); 1064a67a234eSTomasz Miąsko return; 1065a67a234eSTomasz Miąsko } 1066a67a234eSTomasz Miąsko 1067a67a234eSTomasz Miąsko if (Index - 1 >= BoundLifetimes) { 1068a67a234eSTomasz Miąsko Error = true; 1069a67a234eSTomasz Miąsko return; 1070a67a234eSTomasz Miąsko } 1071a67a234eSTomasz Miąsko 1072a67a234eSTomasz Miąsko uint64_t Depth = BoundLifetimes - Index; 1073a67a234eSTomasz Miąsko print('\''); 1074a67a234eSTomasz Miąsko if (Depth < 26) { 1075a67a234eSTomasz Miąsko char C = 'a' + Depth; 1076a67a234eSTomasz Miąsko print(C); 1077a67a234eSTomasz Miąsko } else { 1078a67a234eSTomasz Miąsko print('z'); 1079a67a234eSTomasz Miąsko printDecimalNumber(Depth - 26 + 1); 1080a67a234eSTomasz Miąsko } 1081a67a234eSTomasz Miąsko } 10826cc6ada1STomasz Miąsko 1083c8c2b462STomasz Miąsko static inline bool decodePunycodeDigit(char C, size_t &Value) { 1084c8c2b462STomasz Miąsko if (isLower(C)) { 1085c8c2b462STomasz Miąsko Value = C - 'a'; 1086c8c2b462STomasz Miąsko return true; 1087c8c2b462STomasz Miąsko } 1088c8c2b462STomasz Miąsko 1089c8c2b462STomasz Miąsko if (isDigit(C)) { 1090c8c2b462STomasz Miąsko Value = 26 + (C - '0'); 1091c8c2b462STomasz Miąsko return true; 1092c8c2b462STomasz Miąsko } 1093c8c2b462STomasz Miąsko 1094c8c2b462STomasz Miąsko return false; 1095c8c2b462STomasz Miąsko } 1096c8c2b462STomasz Miąsko 1097*2e97236aSLuís Ferreira static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) { 1098c8c2b462STomasz Miąsko char *Buffer = Output.getBuffer(); 1099c8c2b462STomasz Miąsko char *Start = Buffer + StartIdx; 1100c8c2b462STomasz Miąsko char *End = Buffer + Output.getCurrentPosition(); 1101c8c2b462STomasz Miąsko Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer); 1102c8c2b462STomasz Miąsko } 1103c8c2b462STomasz Miąsko 1104c8c2b462STomasz Miąsko // Encodes code point as UTF-8 and stores results in Output. Returns false if 1105c8c2b462STomasz Miąsko // CodePoint is not a valid unicode scalar value. 1106c8c2b462STomasz Miąsko static inline bool encodeUTF8(size_t CodePoint, char *Output) { 1107c8c2b462STomasz Miąsko if (0xD800 <= CodePoint && CodePoint <= 0xDFFF) 1108c8c2b462STomasz Miąsko return false; 1109c8c2b462STomasz Miąsko 1110c8c2b462STomasz Miąsko if (CodePoint <= 0x7F) { 1111c8c2b462STomasz Miąsko Output[0] = CodePoint; 1112c8c2b462STomasz Miąsko return true; 1113c8c2b462STomasz Miąsko } 1114c8c2b462STomasz Miąsko 1115c8c2b462STomasz Miąsko if (CodePoint <= 0x7FF) { 1116c8c2b462STomasz Miąsko Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F); 1117c8c2b462STomasz Miąsko Output[1] = 0x80 | (CodePoint & 0x3F); 1118c8c2b462STomasz Miąsko return true; 1119c8c2b462STomasz Miąsko } 1120c8c2b462STomasz Miąsko 1121c8c2b462STomasz Miąsko if (CodePoint <= 0xFFFF) { 1122c8c2b462STomasz Miąsko Output[0] = 0xE0 | (CodePoint >> 12); 1123c8c2b462STomasz Miąsko Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F); 1124c8c2b462STomasz Miąsko Output[2] = 0x80 | (CodePoint & 0x3F); 1125c8c2b462STomasz Miąsko return true; 1126c8c2b462STomasz Miąsko } 1127c8c2b462STomasz Miąsko 1128c8c2b462STomasz Miąsko if (CodePoint <= 0x10FFFF) { 1129c8c2b462STomasz Miąsko Output[0] = 0xF0 | (CodePoint >> 18); 1130c8c2b462STomasz Miąsko Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F); 1131c8c2b462STomasz Miąsko Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F); 1132c8c2b462STomasz Miąsko Output[3] = 0x80 | (CodePoint & 0x3F); 1133c8c2b462STomasz Miąsko return true; 1134c8c2b462STomasz Miąsko } 1135c8c2b462STomasz Miąsko 1136c8c2b462STomasz Miąsko return false; 1137c8c2b462STomasz Miąsko } 1138c8c2b462STomasz Miąsko 1139c8c2b462STomasz Miąsko // Decodes string encoded using punycode and appends results to Output. 1140c8c2b462STomasz Miąsko // Returns true if decoding was successful. 1141*2e97236aSLuís Ferreira static bool decodePunycode(StringView Input, OutputBuffer &Output) { 1142c8c2b462STomasz Miąsko size_t OutputSize = Output.getCurrentPosition(); 1143c8c2b462STomasz Miąsko size_t InputIdx = 0; 1144c8c2b462STomasz Miąsko 1145c8c2b462STomasz Miąsko // Rust uses an underscore as a delimiter. 1146c8c2b462STomasz Miąsko size_t DelimiterPos = StringView::npos; 1147c8c2b462STomasz Miąsko for (size_t I = 0; I != Input.size(); ++I) 1148c8c2b462STomasz Miąsko if (Input[I] == '_') 1149c8c2b462STomasz Miąsko DelimiterPos = I; 1150c8c2b462STomasz Miąsko 1151c8c2b462STomasz Miąsko if (DelimiterPos != StringView::npos) { 1152c8c2b462STomasz Miąsko // Copy basic code points before the last delimiter to the output. 1153c8c2b462STomasz Miąsko for (; InputIdx != DelimiterPos; ++InputIdx) { 1154c8c2b462STomasz Miąsko char C = Input[InputIdx]; 1155c8c2b462STomasz Miąsko if (!isValid(C)) 1156c8c2b462STomasz Miąsko return false; 1157c8c2b462STomasz Miąsko // Code points are padded with zeros while decoding is in progress. 1158c8c2b462STomasz Miąsko char UTF8[4] = {C}; 1159c8c2b462STomasz Miąsko Output += StringView(UTF8, UTF8 + 4); 1160c8c2b462STomasz Miąsko } 1161c8c2b462STomasz Miąsko // Skip over the delimiter. 1162c8c2b462STomasz Miąsko ++InputIdx; 1163c8c2b462STomasz Miąsko } 1164c8c2b462STomasz Miąsko 1165c8c2b462STomasz Miąsko size_t Base = 36; 1166c8c2b462STomasz Miąsko size_t Skew = 38; 1167c8c2b462STomasz Miąsko size_t Bias = 72; 1168c8c2b462STomasz Miąsko size_t N = 0x80; 1169c8c2b462STomasz Miąsko size_t TMin = 1; 1170c8c2b462STomasz Miąsko size_t TMax = 26; 1171c8c2b462STomasz Miąsko size_t Damp = 700; 1172c8c2b462STomasz Miąsko 1173c8c2b462STomasz Miąsko auto Adapt = [&](size_t Delta, size_t NumPoints) { 1174c8c2b462STomasz Miąsko Delta /= Damp; 1175c8c2b462STomasz Miąsko Delta += Delta / NumPoints; 1176c8c2b462STomasz Miąsko Damp = 2; 1177c8c2b462STomasz Miąsko 1178c8c2b462STomasz Miąsko size_t K = 0; 1179c8c2b462STomasz Miąsko while (Delta > (Base - TMin) * TMax / 2) { 1180c8c2b462STomasz Miąsko Delta /= Base - TMin; 1181c8c2b462STomasz Miąsko K += Base; 1182c8c2b462STomasz Miąsko } 1183c8c2b462STomasz Miąsko return K + (((Base - TMin + 1) * Delta) / (Delta + Skew)); 1184c8c2b462STomasz Miąsko }; 1185c8c2b462STomasz Miąsko 1186c8c2b462STomasz Miąsko // Main decoding loop. 1187c8c2b462STomasz Miąsko for (size_t I = 0; InputIdx != Input.size(); I += 1) { 1188c8c2b462STomasz Miąsko size_t OldI = I; 1189c8c2b462STomasz Miąsko size_t W = 1; 1190c8c2b462STomasz Miąsko size_t Max = std::numeric_limits<size_t>::max(); 1191c8c2b462STomasz Miąsko for (size_t K = Base; true; K += Base) { 1192c8c2b462STomasz Miąsko if (InputIdx == Input.size()) 1193c8c2b462STomasz Miąsko return false; 1194c8c2b462STomasz Miąsko char C = Input[InputIdx++]; 1195c8c2b462STomasz Miąsko size_t Digit = 0; 1196c8c2b462STomasz Miąsko if (!decodePunycodeDigit(C, Digit)) 1197c8c2b462STomasz Miąsko return false; 1198c8c2b462STomasz Miąsko 1199c8c2b462STomasz Miąsko if (Digit > (Max - I) / W) 1200c8c2b462STomasz Miąsko return false; 1201c8c2b462STomasz Miąsko I += Digit * W; 1202c8c2b462STomasz Miąsko 1203c8c2b462STomasz Miąsko size_t T; 1204c8c2b462STomasz Miąsko if (K <= Bias) 1205c8c2b462STomasz Miąsko T = TMin; 1206c8c2b462STomasz Miąsko else if (K >= Bias + TMax) 1207c8c2b462STomasz Miąsko T = TMax; 1208c8c2b462STomasz Miąsko else 1209c8c2b462STomasz Miąsko T = K - Bias; 1210c8c2b462STomasz Miąsko 1211c8c2b462STomasz Miąsko if (Digit < T) 1212c8c2b462STomasz Miąsko break; 1213c8c2b462STomasz Miąsko 1214c8c2b462STomasz Miąsko if (W > Max / (Base - T)) 1215c8c2b462STomasz Miąsko return false; 1216c8c2b462STomasz Miąsko W *= (Base - T); 1217c8c2b462STomasz Miąsko } 1218c8c2b462STomasz Miąsko size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1; 1219c8c2b462STomasz Miąsko Bias = Adapt(I - OldI, NumPoints); 1220c8c2b462STomasz Miąsko 1221c8c2b462STomasz Miąsko if (I / NumPoints > Max - N) 1222c8c2b462STomasz Miąsko return false; 1223c8c2b462STomasz Miąsko N += I / NumPoints; 1224c8c2b462STomasz Miąsko I = I % NumPoints; 1225c8c2b462STomasz Miąsko 1226c8c2b462STomasz Miąsko // Insert N at position I in the output. 1227c8c2b462STomasz Miąsko char UTF8[4] = {}; 1228c8c2b462STomasz Miąsko if (!encodeUTF8(N, UTF8)) 1229c8c2b462STomasz Miąsko return false; 1230c8c2b462STomasz Miąsko Output.insert(OutputSize + I * 4, UTF8, 4); 1231c8c2b462STomasz Miąsko } 1232c8c2b462STomasz Miąsko 1233c8c2b462STomasz Miąsko removeNullBytes(Output, OutputSize); 1234c8c2b462STomasz Miąsko return true; 1235c8c2b462STomasz Miąsko } 1236c8c2b462STomasz Miąsko 1237c8c2b462STomasz Miąsko void Demangler::printIdentifier(Identifier Ident) { 1238c8c2b462STomasz Miąsko if (Error || !Print) 1239c8c2b462STomasz Miąsko return; 1240c8c2b462STomasz Miąsko 1241c8c2b462STomasz Miąsko if (Ident.Punycode) { 1242c8c2b462STomasz Miąsko if (!decodePunycode(Ident.Name, Output)) 1243c8c2b462STomasz Miąsko Error = true; 1244c8c2b462STomasz Miąsko } else { 1245c8c2b462STomasz Miąsko print(Ident.Name); 1246c8c2b462STomasz Miąsko } 1247c8c2b462STomasz Miąsko } 1248c8c2b462STomasz Miąsko 12496cc6ada1STomasz Miąsko char Demangler::look() const { 12506cc6ada1STomasz Miąsko if (Error || Position >= Input.size()) 12516cc6ada1STomasz Miąsko return 0; 12526cc6ada1STomasz Miąsko 12536cc6ada1STomasz Miąsko return Input[Position]; 12546cc6ada1STomasz Miąsko } 12556cc6ada1STomasz Miąsko 12566cc6ada1STomasz Miąsko char Demangler::consume() { 12576cc6ada1STomasz Miąsko if (Error || Position >= Input.size()) { 12586cc6ada1STomasz Miąsko Error = true; 12596cc6ada1STomasz Miąsko return 0; 12606cc6ada1STomasz Miąsko } 12616cc6ada1STomasz Miąsko 12626cc6ada1STomasz Miąsko return Input[Position++]; 12636cc6ada1STomasz Miąsko } 12646cc6ada1STomasz Miąsko 12656cc6ada1STomasz Miąsko bool Demangler::consumeIf(char Prefix) { 12666cc6ada1STomasz Miąsko if (Error || Position >= Input.size() || Input[Position] != Prefix) 12676cc6ada1STomasz Miąsko return false; 12686cc6ada1STomasz Miąsko 12696cc6ada1STomasz Miąsko Position += 1; 12706cc6ada1STomasz Miąsko return true; 12716cc6ada1STomasz Miąsko } 12726cc6ada1STomasz Miąsko 12736cc6ada1STomasz Miąsko /// Computes A + B. When computation wraps around sets the error and returns 12746cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true. 12756cc6ada1STomasz Miąsko bool Demangler::addAssign(uint64_t &A, uint64_t B) { 12766cc6ada1STomasz Miąsko if (A > std::numeric_limits<uint64_t>::max() - B) { 12776cc6ada1STomasz Miąsko Error = true; 12786cc6ada1STomasz Miąsko return false; 12796cc6ada1STomasz Miąsko } 12806cc6ada1STomasz Miąsko 12816cc6ada1STomasz Miąsko A += B; 12826cc6ada1STomasz Miąsko return true; 12836cc6ada1STomasz Miąsko } 12846cc6ada1STomasz Miąsko 12856cc6ada1STomasz Miąsko /// Computes A * B. When computation wraps around sets the error and returns 12866cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true. 12876cc6ada1STomasz Miąsko bool Demangler::mulAssign(uint64_t &A, uint64_t B) { 12886cc6ada1STomasz Miąsko if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) { 12896cc6ada1STomasz Miąsko Error = true; 12906cc6ada1STomasz Miąsko return false; 12916cc6ada1STomasz Miąsko } 12926cc6ada1STomasz Miąsko 12936cc6ada1STomasz Miąsko A *= B; 12946cc6ada1STomasz Miąsko return true; 12956cc6ada1STomasz Miąsko } 1296