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