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 
262e97236aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer;
2751f6caf2SNathan Sidwell using llvm::itanium_demangle::ScopedOverride;
286cc6ada1STomasz Miąsko using llvm::itanium_demangle::StringView;
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 
empty__anon798090d70111::Identifier366cc6ada1STomasz 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.
912e97236aSLuí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 
demangleBackref(Callable Demangler)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 
12251f6caf2SNathan Sidwell     ScopedOverride<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 
rustDemangle(const char * MangledName)150201c4b9cSNathan Sidwell char *llvm::rustDemangle(const char *MangledName) {
151201c4b9cSNathan Sidwell   if (MangledName == nullptr)
1527310403eSTomasz Miąsko     return nullptr;
1537310403eSTomasz Miąsko 
1547310403eSTomasz Miąsko   // Return early if mangled name doesn't look like a Rust symbol.
1557310403eSTomasz Miąsko   StringView Mangled(MangledName);
156201c4b9cSNathan Sidwell   if (!Mangled.startsWith("_R"))
1577310403eSTomasz Miąsko     return nullptr;
1587310403eSTomasz Miąsko 
1597310403eSTomasz Miąsko   Demangler D;
160*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024))
161*aabeb5ebSKirill Stoimenov     return nullptr;
162*aabeb5ebSKirill Stoimenov 
1637310403eSTomasz Miąsko   if (!D.demangle(Mangled)) {
1647310403eSTomasz Miąsko     std::free(D.Output.getBuffer());
1657310403eSTomasz Miąsko     return nullptr;
1667310403eSTomasz Miąsko   }
1677310403eSTomasz Miąsko 
1687310403eSTomasz Miąsko   D.Output += '\0';
1697310403eSTomasz Miąsko 
170201c4b9cSNathan Sidwell   return D.Output.getBuffer();
1717310403eSTomasz Miąsko }
1727310403eSTomasz Miąsko 
Demangler(size_t MaxRecursionLevel)1737310403eSTomasz Miąsko Demangler::Demangler(size_t MaxRecursionLevel)
1747310403eSTomasz Miąsko     : MaxRecursionLevel(MaxRecursionLevel) {}
1757310403eSTomasz Miąsko 
isDigit(const char C)1767310403eSTomasz Miąsko static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
1777310403eSTomasz Miąsko 
isHexDigit(const char C)178cd74dd17STomasz Miąsko static inline bool isHexDigit(const char C) {
179cd74dd17STomasz Miąsko   return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
180cd74dd17STomasz Miąsko }
181cd74dd17STomasz Miąsko 
isLower(const char C)1827310403eSTomasz Miąsko static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
1837310403eSTomasz Miąsko 
isUpper(const char C)1847310403eSTomasz Miąsko static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
1857310403eSTomasz Miąsko 
1867310403eSTomasz Miąsko /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
isValid(const char C)1877310403eSTomasz Miąsko static inline bool isValid(const char C) {
1887310403eSTomasz Miąsko   return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
1897310403eSTomasz Miąsko }
1907310403eSTomasz Miąsko 
1917310403eSTomasz Miąsko // Demangles Rust v0 mangled symbol. Returns true when successful, and false
1927310403eSTomasz Miąsko // otherwise. The demangled symbol is stored in Output field. It is
1937310403eSTomasz Miąsko // responsibility of the caller to free the memory behind the output stream.
1947310403eSTomasz Miąsko //
1957310403eSTomasz Miąsko // <symbol-name> = "_R" <path> [<instantiating-crate>]
demangle(StringView Mangled)1967310403eSTomasz Miąsko bool Demangler::demangle(StringView Mangled) {
1977310403eSTomasz Miąsko   Position = 0;
1987310403eSTomasz Miąsko   Error = false;
199f0f2a8b2STomasz Miąsko   Print = true;
2007310403eSTomasz Miąsko   RecursionLevel = 0;
201a67a234eSTomasz Miąsko   BoundLifetimes = 0;
2027310403eSTomasz Miąsko 
2037310403eSTomasz Miąsko   if (!Mangled.consumeFront("_R")) {
2047310403eSTomasz Miąsko     Error = true;
2057310403eSTomasz Miąsko     return false;
2067310403eSTomasz Miąsko   }
2072a5bb9c8STomasz Miąsko   size_t Dot = Mangled.find('.');
2082a5bb9c8STomasz Miąsko   Input = Mangled.substr(0, Dot);
2092a5bb9c8STomasz Miąsko   StringView Suffix = Mangled.dropFront(Dot);
2107310403eSTomasz Miąsko 
2116cc6ada1STomasz Miąsko   demanglePath(IsInType::No);
2127310403eSTomasz Miąsko 
21343929cccSTomasz Miąsko   if (Position != Input.size()) {
21451f6caf2SNathan Sidwell     ScopedOverride<bool> SavePrint(Print, false);
2156cc6ada1STomasz Miąsko     demanglePath(IsInType::No);
21643929cccSTomasz Miąsko   }
2177310403eSTomasz Miąsko 
2187310403eSTomasz Miąsko   if (Position != Input.size())
2197310403eSTomasz Miąsko     Error = true;
2207310403eSTomasz Miąsko 
2212a5bb9c8STomasz Miąsko   if (!Suffix.empty()) {
2222a5bb9c8STomasz Miąsko     print(" (");
2232a5bb9c8STomasz Miąsko     print(Suffix);
2242a5bb9c8STomasz Miąsko     print(")");
2252a5bb9c8STomasz Miąsko   }
2262a5bb9c8STomasz Miąsko 
2277310403eSTomasz Miąsko   return !Error;
2287310403eSTomasz Miąsko }
2297310403eSTomasz Miąsko 
230619a65e5STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type. When
231619a65e5STomasz Miąsko // LeaveOpen is true, a closing `>` after generic arguments is omitted from the
232619a65e5STomasz Miąsko // output. Return value indicates whether generics arguments have been left
233619a65e5STomasz Miąsko // open.
23406833297STomasz Miąsko //
2357310403eSTomasz Miąsko // <path> = "C" <identifier>               // crate root
2367310403eSTomasz Miąsko //        | "M" <impl-path> <type>         // <T> (inherent impl)
2377310403eSTomasz Miąsko //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
2387310403eSTomasz Miąsko //        | "Y" <type> <path>              // <T as Trait> (trait definition)
2397310403eSTomasz Miąsko //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
2407310403eSTomasz Miąsko //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
2417310403eSTomasz Miąsko //        | <backref>
2427310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
2437310403eSTomasz Miąsko // <ns> = "C"      // closure
2447310403eSTomasz Miąsko //      | "S"      // shim
2457310403eSTomasz Miąsko //      | <A-Z>    // other special namespaces
2467310403eSTomasz Miąsko //      | <a-z>    // internal namespaces
demanglePath(IsInType InType,LeaveGenericsOpen LeaveOpen)2476cc6ada1STomasz Miąsko bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) {
2487310403eSTomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
2497310403eSTomasz Miąsko     Error = true;
250619a65e5STomasz Miąsko     return false;
2517310403eSTomasz Miąsko   }
25251f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
2537310403eSTomasz Miąsko 
2547310403eSTomasz Miąsko   switch (consume()) {
2557310403eSTomasz Miąsko   case 'C': {
2567310403eSTomasz Miąsko     parseOptionalBase62Number('s');
257c8c2b462STomasz Miąsko     printIdentifier(parseIdentifier());
2587310403eSTomasz Miąsko     break;
2597310403eSTomasz Miąsko   }
260f0f2a8b2STomasz Miąsko   case 'M': {
26106833297STomasz Miąsko     demangleImplPath(InType);
262f0f2a8b2STomasz Miąsko     print("<");
263f0f2a8b2STomasz Miąsko     demangleType();
264f0f2a8b2STomasz Miąsko     print(">");
265f0f2a8b2STomasz Miąsko     break;
266f0f2a8b2STomasz Miąsko   }
2679fa13800STomasz Miąsko   case 'X': {
26806833297STomasz Miąsko     demangleImplPath(InType);
2699fa13800STomasz Miąsko     print("<");
2709fa13800STomasz Miąsko     demangleType();
2719fa13800STomasz Miąsko     print(" as ");
2726cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
2739fa13800STomasz Miąsko     print(">");
2749fa13800STomasz Miąsko     break;
2759fa13800STomasz Miąsko   }
276f933f7fbSTomasz Miąsko   case 'Y': {
277f933f7fbSTomasz Miąsko     print("<");
278f933f7fbSTomasz Miąsko     demangleType();
279f933f7fbSTomasz Miąsko     print(" as ");
2806cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
281f933f7fbSTomasz Miąsko     print(">");
282f933f7fbSTomasz Miąsko     break;
283f933f7fbSTomasz Miąsko   }
2847310403eSTomasz Miąsko   case 'N': {
2857310403eSTomasz Miąsko     char NS = consume();
2867310403eSTomasz Miąsko     if (!isLower(NS) && !isUpper(NS)) {
2877310403eSTomasz Miąsko       Error = true;
2887310403eSTomasz Miąsko       break;
2897310403eSTomasz Miąsko     }
29006833297STomasz Miąsko     demanglePath(InType);
2917310403eSTomasz Miąsko 
29278e94915STomasz Miąsko     uint64_t Disambiguator = parseOptionalBase62Number('s');
2937310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
2947310403eSTomasz Miąsko 
29578e94915STomasz Miąsko     if (isUpper(NS)) {
29678e94915STomasz Miąsko       // Special namespaces
29778e94915STomasz Miąsko       print("::{");
29878e94915STomasz Miąsko       if (NS == 'C')
29978e94915STomasz Miąsko         print("closure");
30078e94915STomasz Miąsko       else if (NS == 'S')
30178e94915STomasz Miąsko         print("shim");
30278e94915STomasz Miąsko       else
30378e94915STomasz Miąsko         print(NS);
3047310403eSTomasz Miąsko       if (!Ident.empty()) {
30578e94915STomasz Miąsko         print(":");
306c8c2b462STomasz Miąsko         printIdentifier(Ident);
30778e94915STomasz Miąsko       }
30878e94915STomasz Miąsko       print('#');
30978e94915STomasz Miąsko       printDecimalNumber(Disambiguator);
31078e94915STomasz Miąsko       print('}');
31178e94915STomasz Miąsko     } else {
31278e94915STomasz Miąsko       // Implementation internal namespaces.
31378e94915STomasz Miąsko       if (!Ident.empty()) {
3147310403eSTomasz Miąsko         print("::");
315c8c2b462STomasz Miąsko         printIdentifier(Ident);
3167310403eSTomasz Miąsko       }
31778e94915STomasz Miąsko     }
3187310403eSTomasz Miąsko     break;
3197310403eSTomasz Miąsko   }
3202961f863STomasz Miąsko   case 'I': {
32106833297STomasz Miąsko     demanglePath(InType);
32206833297STomasz Miąsko     // Omit "::" when in a type, where it is optional.
3236cc6ada1STomasz Miąsko     if (InType == IsInType::No)
32406833297STomasz Miąsko       print("::");
32506833297STomasz Miąsko     print("<");
3262961f863STomasz Miąsko     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
3272961f863STomasz Miąsko       if (I > 0)
3282961f863STomasz Miąsko         print(", ");
3292961f863STomasz Miąsko       demangleGenericArg();
3302961f863STomasz Miąsko     }
3316cc6ada1STomasz Miąsko     if (LeaveOpen == LeaveGenericsOpen::Yes)
332619a65e5STomasz Miąsko       return true;
333619a65e5STomasz Miąsko     else
3342961f863STomasz Miąsko       print(">");
3352961f863STomasz Miąsko     break;
3362961f863STomasz Miąsko   }
33782b7e822STomasz Miąsko   case 'B': {
33882b7e822STomasz Miąsko     bool IsOpen = false;
33982b7e822STomasz Miąsko     demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
34082b7e822STomasz Miąsko     return IsOpen;
34182b7e822STomasz Miąsko   }
3427310403eSTomasz Miąsko   default:
3437310403eSTomasz Miąsko     Error = true;
3447310403eSTomasz Miąsko     break;
3457310403eSTomasz Miąsko   }
346619a65e5STomasz Miąsko 
347619a65e5STomasz Miąsko   return false;
3487310403eSTomasz Miąsko }
3497310403eSTomasz Miąsko 
350f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path>
351f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number>
demangleImplPath(IsInType InType)3526cc6ada1STomasz Miąsko void Demangler::demangleImplPath(IsInType InType) {
35351f6caf2SNathan Sidwell   ScopedOverride<bool> SavePrint(Print, false);
354f0f2a8b2STomasz Miąsko   parseOptionalBase62Number('s');
35506833297STomasz Miąsko   demanglePath(InType);
356f0f2a8b2STomasz Miąsko }
357f0f2a8b2STomasz Miąsko 
3582961f863STomasz Miąsko // <generic-arg> = <lifetime>
3592961f863STomasz Miąsko //               | <type>
3602961f863STomasz Miąsko //               | "K" <const>
3612961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
demangleGenericArg()3622961f863STomasz Miąsko void Demangler::demangleGenericArg() {
363a67a234eSTomasz Miąsko   if (consumeIf('L'))
364a67a234eSTomasz Miąsko     printLifetime(parseBase62Number());
365a67a234eSTomasz Miąsko   else if (consumeIf('K'))
366cd74dd17STomasz Miąsko     demangleConst();
367cd74dd17STomasz Miąsko   else
3682961f863STomasz Miąsko     demangleType();
3692961f863STomasz Miąsko }
3702961f863STomasz Miąsko 
3712961f863STomasz Miąsko // <basic-type> = "a"      // i8
3722961f863STomasz Miąsko //              | "b"      // bool
3732961f863STomasz Miąsko //              | "c"      // char
3742961f863STomasz Miąsko //              | "d"      // f64
3752961f863STomasz Miąsko //              | "e"      // str
3762961f863STomasz Miąsko //              | "f"      // f32
3772961f863STomasz Miąsko //              | "h"      // u8
3782961f863STomasz Miąsko //              | "i"      // isize
3792961f863STomasz Miąsko //              | "j"      // usize
3802961f863STomasz Miąsko //              | "l"      // i32
3812961f863STomasz Miąsko //              | "m"      // u32
3822961f863STomasz Miąsko //              | "n"      // i128
3832961f863STomasz Miąsko //              | "o"      // u128
3842961f863STomasz Miąsko //              | "s"      // i16
3852961f863STomasz Miąsko //              | "t"      // u16
3862961f863STomasz Miąsko //              | "u"      // ()
3872961f863STomasz Miąsko //              | "v"      // ...
3882961f863STomasz Miąsko //              | "x"      // i64
3892961f863STomasz Miąsko //              | "y"      // u64
3902961f863STomasz Miąsko //              | "z"      // !
3912961f863STomasz Miąsko //              | "p"      // placeholder (e.g. for generic params), shown as _
parseBasicType(char C,BasicType & Type)392cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
393cd74dd17STomasz Miąsko   switch (C) {
394cd74dd17STomasz Miąsko   case 'a':
395cd74dd17STomasz Miąsko     Type = BasicType::I8;
396cd74dd17STomasz Miąsko     return true;
397cd74dd17STomasz Miąsko   case 'b':
398cd74dd17STomasz Miąsko     Type = BasicType::Bool;
399cd74dd17STomasz Miąsko     return true;
400cd74dd17STomasz Miąsko   case 'c':
401cd74dd17STomasz Miąsko     Type = BasicType::Char;
402cd74dd17STomasz Miąsko     return true;
403cd74dd17STomasz Miąsko   case 'd':
404cd74dd17STomasz Miąsko     Type = BasicType::F64;
405cd74dd17STomasz Miąsko     return true;
406cd74dd17STomasz Miąsko   case 'e':
407cd74dd17STomasz Miąsko     Type = BasicType::Str;
408cd74dd17STomasz Miąsko     return true;
409cd74dd17STomasz Miąsko   case 'f':
410cd74dd17STomasz Miąsko     Type = BasicType::F32;
411cd74dd17STomasz Miąsko     return true;
412cd74dd17STomasz Miąsko   case 'h':
413cd74dd17STomasz Miąsko     Type = BasicType::U8;
414cd74dd17STomasz Miąsko     return true;
415cd74dd17STomasz Miąsko   case 'i':
416cd74dd17STomasz Miąsko     Type = BasicType::ISize;
417cd74dd17STomasz Miąsko     return true;
418cd74dd17STomasz Miąsko   case 'j':
419cd74dd17STomasz Miąsko     Type = BasicType::USize;
420cd74dd17STomasz Miąsko     return true;
421cd74dd17STomasz Miąsko   case 'l':
422cd74dd17STomasz Miąsko     Type = BasicType::I32;
423cd74dd17STomasz Miąsko     return true;
424cd74dd17STomasz Miąsko   case 'm':
425cd74dd17STomasz Miąsko     Type = BasicType::U32;
426cd74dd17STomasz Miąsko     return true;
427cd74dd17STomasz Miąsko   case 'n':
428cd74dd17STomasz Miąsko     Type = BasicType::I128;
429cd74dd17STomasz Miąsko     return true;
430cd74dd17STomasz Miąsko   case 'o':
431cd74dd17STomasz Miąsko     Type = BasicType::U128;
432cd74dd17STomasz Miąsko     return true;
433cd74dd17STomasz Miąsko   case 'p':
434cd74dd17STomasz Miąsko     Type = BasicType::Placeholder;
435cd74dd17STomasz Miąsko     return true;
436cd74dd17STomasz Miąsko   case 's':
437cd74dd17STomasz Miąsko     Type = BasicType::I16;
438cd74dd17STomasz Miąsko     return true;
439cd74dd17STomasz Miąsko   case 't':
440cd74dd17STomasz Miąsko     Type = BasicType::U16;
441cd74dd17STomasz Miąsko     return true;
442cd74dd17STomasz Miąsko   case 'u':
443cd74dd17STomasz Miąsko     Type = BasicType::Unit;
444cd74dd17STomasz Miąsko     return true;
445cd74dd17STomasz Miąsko   case 'v':
446cd74dd17STomasz Miąsko     Type = BasicType::Variadic;
447cd74dd17STomasz Miąsko     return true;
448cd74dd17STomasz Miąsko   case 'x':
449cd74dd17STomasz Miąsko     Type = BasicType::I64;
450cd74dd17STomasz Miąsko     return true;
451cd74dd17STomasz Miąsko   case 'y':
452cd74dd17STomasz Miąsko     Type = BasicType::U64;
453cd74dd17STomasz Miąsko     return true;
454cd74dd17STomasz Miąsko   case 'z':
455cd74dd17STomasz Miąsko     Type = BasicType::Never;
456cd74dd17STomasz Miąsko     return true;
457cd74dd17STomasz Miąsko   default:
458cd74dd17STomasz Miąsko     return false;
459cd74dd17STomasz Miąsko   }
460cd74dd17STomasz Miąsko }
461cd74dd17STomasz Miąsko 
printBasicType(BasicType Type)462cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
463cd74dd17STomasz Miąsko   switch (Type) {
464cd74dd17STomasz Miąsko   case BasicType::Bool:
465cd74dd17STomasz Miąsko     print("bool");
466cd74dd17STomasz Miąsko     break;
467cd74dd17STomasz Miąsko   case BasicType::Char:
468cd74dd17STomasz Miąsko     print("char");
469cd74dd17STomasz Miąsko     break;
470cd74dd17STomasz Miąsko   case BasicType::I8:
471cd74dd17STomasz Miąsko     print("i8");
472cd74dd17STomasz Miąsko     break;
473cd74dd17STomasz Miąsko   case BasicType::I16:
474cd74dd17STomasz Miąsko     print("i16");
475cd74dd17STomasz Miąsko     break;
476cd74dd17STomasz Miąsko   case BasicType::I32:
477cd74dd17STomasz Miąsko     print("i32");
478cd74dd17STomasz Miąsko     break;
479cd74dd17STomasz Miąsko   case BasicType::I64:
480cd74dd17STomasz Miąsko     print("i64");
481cd74dd17STomasz Miąsko     break;
482cd74dd17STomasz Miąsko   case BasicType::I128:
483cd74dd17STomasz Miąsko     print("i128");
484cd74dd17STomasz Miąsko     break;
485cd74dd17STomasz Miąsko   case BasicType::ISize:
486cd74dd17STomasz Miąsko     print("isize");
487cd74dd17STomasz Miąsko     break;
488cd74dd17STomasz Miąsko   case BasicType::U8:
489cd74dd17STomasz Miąsko     print("u8");
490cd74dd17STomasz Miąsko     break;
491cd74dd17STomasz Miąsko   case BasicType::U16:
492cd74dd17STomasz Miąsko     print("u16");
493cd74dd17STomasz Miąsko     break;
494cd74dd17STomasz Miąsko   case BasicType::U32:
495cd74dd17STomasz Miąsko     print("u32");
496cd74dd17STomasz Miąsko     break;
497cd74dd17STomasz Miąsko   case BasicType::U64:
498cd74dd17STomasz Miąsko     print("u64");
499cd74dd17STomasz Miąsko     break;
500cd74dd17STomasz Miąsko   case BasicType::U128:
501cd74dd17STomasz Miąsko     print("u128");
502cd74dd17STomasz Miąsko     break;
503cd74dd17STomasz Miąsko   case BasicType::USize:
504cd74dd17STomasz Miąsko     print("usize");
505cd74dd17STomasz Miąsko     break;
506cd74dd17STomasz Miąsko   case BasicType::F32:
507cd74dd17STomasz Miąsko     print("f32");
508cd74dd17STomasz Miąsko     break;
509cd74dd17STomasz Miąsko   case BasicType::F64:
510cd74dd17STomasz Miąsko     print("f64");
511cd74dd17STomasz Miąsko     break;
512cd74dd17STomasz Miąsko   case BasicType::Str:
513cd74dd17STomasz Miąsko     print("str");
514cd74dd17STomasz Miąsko     break;
515cd74dd17STomasz Miąsko   case BasicType::Placeholder:
516cd74dd17STomasz Miąsko     print("_");
517cd74dd17STomasz Miąsko     break;
518cd74dd17STomasz Miąsko   case BasicType::Unit:
519cd74dd17STomasz Miąsko     print("()");
520cd74dd17STomasz Miąsko     break;
521cd74dd17STomasz Miąsko   case BasicType::Variadic:
522cd74dd17STomasz Miąsko     print("...");
523cd74dd17STomasz Miąsko     break;
524cd74dd17STomasz Miąsko   case BasicType::Never:
525cd74dd17STomasz Miąsko     print("!");
526cd74dd17STomasz Miąsko     break;
527cd74dd17STomasz Miąsko   }
5282961f863STomasz Miąsko }
5292961f863STomasz Miąsko 
5302961f863STomasz Miąsko // <type> = | <basic-type>
5312961f863STomasz Miąsko //          | <path>                      // named type
5322961f863STomasz Miąsko //          | "A" <type> <const>          // [T; N]
5332961f863STomasz Miąsko //          | "S" <type>                  // [T]
5342961f863STomasz Miąsko //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
5352961f863STomasz Miąsko //          | "R" [<lifetime>] <type>     // &T
5362961f863STomasz Miąsko //          | "Q" [<lifetime>] <type>     // &mut T
5372961f863STomasz Miąsko //          | "P" <type>                  // *const T
5382961f863STomasz Miąsko //          | "O" <type>                  // *mut T
5392961f863STomasz Miąsko //          | "F" <fn-sig>                // fn(...) -> ...
5402961f863STomasz Miąsko //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
5412961f863STomasz Miąsko //          | <backref>                   // backref
demangleType()5422961f863STomasz Miąsko void Demangler::demangleType() {
54344d63c57STomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
54444d63c57STomasz Miąsko     Error = true;
54544d63c57STomasz Miąsko     return;
54644d63c57STomasz Miąsko   }
54751f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
54806833297STomasz Miąsko 
54944d63c57STomasz Miąsko   size_t Start = Position;
550b42400ccSTomasz Miąsko   char C = consume();
551b42400ccSTomasz Miąsko   BasicType Type;
552b42400ccSTomasz Miąsko   if (parseBasicType(C, Type))
553b42400ccSTomasz Miąsko     return printBasicType(Type);
554b42400ccSTomasz Miąsko 
555b42400ccSTomasz Miąsko   switch (C) {
556b42400ccSTomasz Miąsko   case 'A':
557b42400ccSTomasz Miąsko     print("[");
558b42400ccSTomasz Miąsko     demangleType();
559b42400ccSTomasz Miąsko     print("; ");
560b42400ccSTomasz Miąsko     demangleConst();
561b42400ccSTomasz Miąsko     print("]");
562b42400ccSTomasz Miąsko     break;
563a84c65c2STomasz Miąsko   case 'S':
564a84c65c2STomasz Miąsko     print("[");
565a84c65c2STomasz Miąsko     demangleType();
566a84c65c2STomasz Miąsko     print("]");
567a84c65c2STomasz Miąsko     break;
568774de7a0STomasz Miąsko   case 'T': {
569774de7a0STomasz Miąsko     print("(");
570774de7a0STomasz Miąsko     size_t I = 0;
571774de7a0STomasz Miąsko     for (; !Error && !consumeIf('E'); ++I) {
572774de7a0STomasz Miąsko       if (I > 0)
573774de7a0STomasz Miąsko         print(", ");
574774de7a0STomasz Miąsko       demangleType();
575774de7a0STomasz Miąsko     }
576774de7a0STomasz Miąsko     if (I == 1)
577774de7a0STomasz Miąsko       print(",");
578774de7a0STomasz Miąsko     print(")");
579774de7a0STomasz Miąsko     break;
580774de7a0STomasz Miąsko   }
581e4fa6c95STomasz Miąsko   case 'R':
582e4fa6c95STomasz Miąsko   case 'Q':
583a67a234eSTomasz Miąsko     print('&');
584a67a234eSTomasz Miąsko     if (consumeIf('L')) {
585a67a234eSTomasz Miąsko       if (auto Lifetime = parseBase62Number()) {
586a67a234eSTomasz Miąsko         printLifetime(Lifetime);
587a67a234eSTomasz Miąsko         print(' ');
588a67a234eSTomasz Miąsko       }
589a67a234eSTomasz Miąsko     }
590a67a234eSTomasz Miąsko     if (C == 'Q')
591a67a234eSTomasz Miąsko       print("mut ");
592e4fa6c95STomasz Miąsko     demangleType();
593e4fa6c95STomasz Miąsko     break;
5946aac5633STomasz Miąsko   case 'P':
5956aac5633STomasz Miąsko     print("*const ");
5966aac5633STomasz Miąsko     demangleType();
5976aac5633STomasz Miąsko     break;
5986aac5633STomasz Miąsko   case 'O':
5996aac5633STomasz Miąsko     print("*mut ");
6006aac5633STomasz Miąsko     demangleType();
6016aac5633STomasz Miąsko     break;
60275cc1cf0STomasz Miąsko   case 'F':
60375cc1cf0STomasz Miąsko     demangleFnSig();
60475cc1cf0STomasz Miąsko     break;
60589615a5eSTomasz Miąsko   case 'D':
60689615a5eSTomasz Miąsko     demangleDynBounds();
60789615a5eSTomasz Miąsko     if (consumeIf('L')) {
60889615a5eSTomasz Miąsko       if (auto Lifetime = parseBase62Number()) {
60989615a5eSTomasz Miąsko         print(" + ");
61089615a5eSTomasz Miąsko         printLifetime(Lifetime);
61189615a5eSTomasz Miąsko       }
61289615a5eSTomasz Miąsko     } else {
61389615a5eSTomasz Miąsko       Error = true;
61489615a5eSTomasz Miąsko     }
61589615a5eSTomasz Miąsko     break;
61644d63c57STomasz Miąsko   case 'B':
61744d63c57STomasz Miąsko     demangleBackref([&] { demangleType(); });
61844d63c57STomasz Miąsko     break;
619b42400ccSTomasz Miąsko   default:
620b42400ccSTomasz Miąsko     Position = Start;
6216cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
622b42400ccSTomasz Miąsko     break;
623b42400ccSTomasz Miąsko   }
624cd74dd17STomasz Miąsko }
625cd74dd17STomasz Miąsko 
62675cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
62775cc1cf0STomasz Miąsko // <abi> = "C"
62875cc1cf0STomasz Miąsko //       | <undisambiguated-identifier>
demangleFnSig()62975cc1cf0STomasz Miąsko void Demangler::demangleFnSig() {
63051f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
631a67a234eSTomasz Miąsko   demangleOptionalBinder();
63275cc1cf0STomasz Miąsko 
63375cc1cf0STomasz Miąsko   if (consumeIf('U'))
63475cc1cf0STomasz Miąsko     print("unsafe ");
63575cc1cf0STomasz Miąsko 
63675cc1cf0STomasz Miąsko   if (consumeIf('K')) {
63775cc1cf0STomasz Miąsko     print("extern \"");
63875cc1cf0STomasz Miąsko     if (consumeIf('C')) {
63975cc1cf0STomasz Miąsko       print("C");
64075cc1cf0STomasz Miąsko     } else {
64175cc1cf0STomasz Miąsko       Identifier Ident = parseIdentifier();
642c8c2b462STomasz Miąsko       if (Ident.Punycode)
643c8c2b462STomasz Miąsko         Error = true;
64475cc1cf0STomasz Miąsko       for (char C : Ident.Name) {
64575cc1cf0STomasz Miąsko         // When mangling ABI string, the "-" is replaced with "_".
64675cc1cf0STomasz Miąsko         if (C == '_')
64775cc1cf0STomasz Miąsko           C = '-';
64875cc1cf0STomasz Miąsko         print(C);
64975cc1cf0STomasz Miąsko       }
65075cc1cf0STomasz Miąsko     }
65175cc1cf0STomasz Miąsko     print("\" ");
65275cc1cf0STomasz Miąsko   }
65375cc1cf0STomasz Miąsko 
65475cc1cf0STomasz Miąsko   print("fn(");
65575cc1cf0STomasz Miąsko   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
65675cc1cf0STomasz Miąsko     if (I > 0)
65775cc1cf0STomasz Miąsko       print(", ");
65875cc1cf0STomasz Miąsko     demangleType();
65975cc1cf0STomasz Miąsko   }
66075cc1cf0STomasz Miąsko   print(")");
66175cc1cf0STomasz Miąsko 
66275cc1cf0STomasz Miąsko   if (consumeIf('u')) {
66375cc1cf0STomasz Miąsko     // Skip the unit type from the output.
66475cc1cf0STomasz Miąsko   } else {
66575cc1cf0STomasz Miąsko     print(" -> ");
66675cc1cf0STomasz Miąsko     demangleType();
66775cc1cf0STomasz Miąsko   }
66875cc1cf0STomasz Miąsko }
66975cc1cf0STomasz Miąsko 
67089615a5eSTomasz Miąsko // <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
demangleDynBounds()67189615a5eSTomasz Miąsko void Demangler::demangleDynBounds() {
67251f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
67389615a5eSTomasz Miąsko   print("dyn ");
67489615a5eSTomasz Miąsko   demangleOptionalBinder();
6751499afa0STomasz Miąsko   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
6761499afa0STomasz Miąsko     if (I > 0)
6771499afa0STomasz Miąsko       print(" + ");
6781499afa0STomasz Miąsko     demangleDynTrait();
6791499afa0STomasz Miąsko   }
6801499afa0STomasz Miąsko }
6811499afa0STomasz Miąsko 
6821499afa0STomasz Miąsko // <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
6831499afa0STomasz Miąsko // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
demangleDynTrait()6841499afa0STomasz Miąsko void Demangler::demangleDynTrait() {
6856cc6ada1STomasz Miąsko   bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes);
686619a65e5STomasz Miąsko   while (!Error && consumeIf('p')) {
687619a65e5STomasz Miąsko     if (!IsOpen) {
688619a65e5STomasz Miąsko       IsOpen = true;
689619a65e5STomasz Miąsko       print('<');
690619a65e5STomasz Miąsko     } else {
691619a65e5STomasz Miąsko       print(", ");
692619a65e5STomasz Miąsko     }
693619a65e5STomasz Miąsko     print(parseIdentifier().Name);
694619a65e5STomasz Miąsko     print(" = ");
695619a65e5STomasz Miąsko     demangleType();
696619a65e5STomasz Miąsko   }
697619a65e5STomasz Miąsko   if (IsOpen)
698619a65e5STomasz Miąsko     print(">");
69989615a5eSTomasz Miąsko }
70089615a5eSTomasz Miąsko 
701a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes.
702a67a234eSTomasz Miąsko //
703a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number>
demangleOptionalBinder()704a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() {
705a67a234eSTomasz Miąsko   uint64_t Binder = parseOptionalBase62Number('G');
706a67a234eSTomasz Miąsko   if (Error || Binder == 0)
707a67a234eSTomasz Miąsko     return;
708a67a234eSTomasz Miąsko 
709a67a234eSTomasz Miąsko   // In valid inputs each bound lifetime is referenced later. Referencing a
710a67a234eSTomasz Miąsko   // lifetime requires at least one byte of input. Reject inputs that are too
711a67a234eSTomasz Miąsko   // short to reference all bound lifetimes. Otherwise demangling of invalid
712a67a234eSTomasz Miąsko   // binders could generate excessive amounts of output.
713a67a234eSTomasz Miąsko   if (Binder >= Input.size() - BoundLifetimes) {
714a67a234eSTomasz Miąsko     Error = true;
715a67a234eSTomasz Miąsko     return;
716a67a234eSTomasz Miąsko   }
717a67a234eSTomasz Miąsko 
718a67a234eSTomasz Miąsko   print("for<");
719a67a234eSTomasz Miąsko   for (size_t I = 0; I != Binder; ++I) {
720a67a234eSTomasz Miąsko     BoundLifetimes += 1;
721a67a234eSTomasz Miąsko     if (I > 0)
722a67a234eSTomasz Miąsko       print(", ");
723a67a234eSTomasz Miąsko     printLifetime(1);
724a67a234eSTomasz Miąsko   }
725a67a234eSTomasz Miąsko   print("> ");
726a67a234eSTomasz Miąsko }
727a67a234eSTomasz Miąsko 
728cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
729cd74dd17STomasz Miąsko //         | "p"                          // placeholder
730cd74dd17STomasz Miąsko //         | <backref>
demangleConst()731cd74dd17STomasz Miąsko void Demangler::demangleConst() {
732f9a79356STomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
733f9a79356STomasz Miąsko     Error = true;
734f9a79356STomasz Miąsko     return;
735f9a79356STomasz Miąsko   }
73651f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
737f9a79356STomasz Miąsko 
738f9a79356STomasz Miąsko   char C = consume();
739cd74dd17STomasz Miąsko   BasicType Type;
740f9a79356STomasz Miąsko   if (parseBasicType(C, Type)) {
741cd74dd17STomasz Miąsko     switch (Type) {
742cd74dd17STomasz Miąsko     case BasicType::I8:
743cd74dd17STomasz Miąsko     case BasicType::I16:
744cd74dd17STomasz Miąsko     case BasicType::I32:
745cd74dd17STomasz Miąsko     case BasicType::I64:
746cd74dd17STomasz Miąsko     case BasicType::I128:
747cd74dd17STomasz Miąsko     case BasicType::ISize:
748cd74dd17STomasz Miąsko     case BasicType::U8:
749cd74dd17STomasz Miąsko     case BasicType::U16:
750cd74dd17STomasz Miąsko     case BasicType::U32:
751cd74dd17STomasz Miąsko     case BasicType::U64:
752cd74dd17STomasz Miąsko     case BasicType::U128:
753cd74dd17STomasz Miąsko     case BasicType::USize:
754cd74dd17STomasz Miąsko       demangleConstInt();
755cd74dd17STomasz Miąsko       break;
756fc0f2bb9STomasz Miąsko     case BasicType::Bool:
757fc0f2bb9STomasz Miąsko       demangleConstBool();
758fc0f2bb9STomasz Miąsko       break;
7592ba49f6aSTomasz Miąsko     case BasicType::Char:
7602ba49f6aSTomasz Miąsko       demangleConstChar();
7612ba49f6aSTomasz Miąsko       break;
762cd74dd17STomasz Miąsko     case BasicType::Placeholder:
763cd74dd17STomasz Miąsko       print('_');
764cd74dd17STomasz Miąsko       break;
765cd74dd17STomasz Miąsko     default:
7662961f863STomasz Miąsko       Error = true;
767cd74dd17STomasz Miąsko       break;
768cd74dd17STomasz Miąsko     }
769f9a79356STomasz Miąsko   } else if (C == 'B') {
770f9a79356STomasz Miąsko     demangleBackref([&] { demangleConst(); });
771cd74dd17STomasz Miąsko   } else {
772cd74dd17STomasz Miąsko     Error = true;
773cd74dd17STomasz Miąsko   }
774cd74dd17STomasz Miąsko }
775cd74dd17STomasz Miąsko 
776cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
demangleConstInt()777cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
778cd74dd17STomasz Miąsko   if (consumeIf('n'))
779cd74dd17STomasz Miąsko     print('-');
780cd74dd17STomasz Miąsko 
781cd74dd17STomasz Miąsko   StringView HexDigits;
782cd74dd17STomasz Miąsko   uint64_t Value = parseHexNumber(HexDigits);
783cd74dd17STomasz Miąsko   if (HexDigits.size() <= 16) {
784cd74dd17STomasz Miąsko     printDecimalNumber(Value);
785cd74dd17STomasz Miąsko   } else {
786cd74dd17STomasz Miąsko     print("0x");
787cd74dd17STomasz Miąsko     print(HexDigits);
7882961f863STomasz Miąsko   }
7892961f863STomasz Miąsko }
7902961f863STomasz Miąsko 
791fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
792fc0f2bb9STomasz Miąsko //              | "1_" // true
demangleConstBool()793fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
794fc0f2bb9STomasz Miąsko   StringView HexDigits;
795fc0f2bb9STomasz Miąsko   parseHexNumber(HexDigits);
796fc0f2bb9STomasz Miąsko   if (HexDigits == "0")
797fc0f2bb9STomasz Miąsko     print("false");
798fc0f2bb9STomasz Miąsko   else if (HexDigits == "1")
799fc0f2bb9STomasz Miąsko     print("true");
800fc0f2bb9STomasz Miąsko   else
801fc0f2bb9STomasz Miąsko     Error = true;
802fc0f2bb9STomasz Miąsko }
803fc0f2bb9STomasz Miąsko 
8042ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character.
isAsciiPrintable(uint64_t CodePoint)8052ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) {
8062ba49f6aSTomasz Miąsko   return 0x20 <= CodePoint && CodePoint <= 0x7e;
8072ba49f6aSTomasz Miąsko }
8082ba49f6aSTomasz Miąsko 
8092ba49f6aSTomasz Miąsko // <const-data> = <hex-number>
demangleConstChar()8102ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() {
8112ba49f6aSTomasz Miąsko   StringView HexDigits;
8122ba49f6aSTomasz Miąsko   uint64_t CodePoint = parseHexNumber(HexDigits);
8132ba49f6aSTomasz Miąsko   if (Error || HexDigits.size() > 6) {
8142ba49f6aSTomasz Miąsko     Error = true;
8152ba49f6aSTomasz Miąsko     return;
8162ba49f6aSTomasz Miąsko   }
8172ba49f6aSTomasz Miąsko 
8182ba49f6aSTomasz Miąsko   print("'");
8192ba49f6aSTomasz Miąsko   switch (CodePoint) {
8202ba49f6aSTomasz Miąsko   case '\t':
8212ba49f6aSTomasz Miąsko     print(R"(\t)");
8222ba49f6aSTomasz Miąsko     break;
8232ba49f6aSTomasz Miąsko   case '\r':
8242ba49f6aSTomasz Miąsko     print(R"(\r)");
8252ba49f6aSTomasz Miąsko     break;
8262ba49f6aSTomasz Miąsko   case '\n':
8272ba49f6aSTomasz Miąsko     print(R"(\n)");
8282ba49f6aSTomasz Miąsko     break;
8292ba49f6aSTomasz Miąsko   case '\\':
8302ba49f6aSTomasz Miąsko     print(R"(\\)");
8312ba49f6aSTomasz Miąsko     break;
8322ba49f6aSTomasz Miąsko   case '"':
8332ba49f6aSTomasz Miąsko     print(R"(")");
8342ba49f6aSTomasz Miąsko     break;
8352ba49f6aSTomasz Miąsko   case '\'':
8362ba49f6aSTomasz Miąsko     print(R"(\')");
8372ba49f6aSTomasz Miąsko     break;
8382ba49f6aSTomasz Miąsko   default:
8392ba49f6aSTomasz Miąsko     if (isAsciiPrintable(CodePoint)) {
8402ba49f6aSTomasz Miąsko       char C = CodePoint;
8412ba49f6aSTomasz Miąsko       print(C);
8422ba49f6aSTomasz Miąsko     } else {
8432ba49f6aSTomasz Miąsko       print(R"(\u{)");
8442ba49f6aSTomasz Miąsko       print(HexDigits);
8452ba49f6aSTomasz Miąsko       print('}');
8462ba49f6aSTomasz Miąsko     }
8472ba49f6aSTomasz Miąsko     break;
8482ba49f6aSTomasz Miąsko   }
8492ba49f6aSTomasz Miąsko   print('\'');
8502ba49f6aSTomasz Miąsko }
8512ba49f6aSTomasz Miąsko 
8527310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
parseIdentifier()8537310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
8547310403eSTomasz Miąsko   bool Punycode = consumeIf('u');
8557310403eSTomasz Miąsko   uint64_t Bytes = parseDecimalNumber();
8567310403eSTomasz Miąsko 
8577310403eSTomasz Miąsko   // Underscore resolves the ambiguity when identifier starts with a decimal
8587310403eSTomasz Miąsko   // digit or another underscore.
8597310403eSTomasz Miąsko   consumeIf('_');
8607310403eSTomasz Miąsko 
8617310403eSTomasz Miąsko   if (Error || Bytes > Input.size() - Position) {
8627310403eSTomasz Miąsko     Error = true;
8637310403eSTomasz Miąsko     return {};
8647310403eSTomasz Miąsko   }
8657310403eSTomasz Miąsko   StringView S = Input.substr(Position, Bytes);
8667310403eSTomasz Miąsko   Position += Bytes;
8677310403eSTomasz Miąsko 
8687310403eSTomasz Miąsko   if (!std::all_of(S.begin(), S.end(), isValid)) {
8697310403eSTomasz Miąsko     Error = true;
8707310403eSTomasz Miąsko     return {};
8717310403eSTomasz Miąsko   }
8727310403eSTomasz Miąsko 
8737310403eSTomasz Miąsko   return {S, Punycode};
8747310403eSTomasz Miąsko }
8757310403eSTomasz Miąsko 
8767310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
877a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
878a67a234eSTomasz Miąsko //
879a67a234eSTomasz Miąsko // This function is indended for parsing disambiguators and binders which when
880a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded
881a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
882a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0.
parseOptionalBase62Number(char Tag)88378e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
88478e94915STomasz Miąsko   if (!consumeIf(Tag))
88578e94915STomasz Miąsko     return 0;
88678e94915STomasz Miąsko 
88778e94915STomasz Miąsko   uint64_t N = parseBase62Number();
88878e94915STomasz Miąsko   if (Error || !addAssign(N, 1))
88978e94915STomasz Miąsko     return 0;
89078e94915STomasz Miąsko 
89178e94915STomasz Miąsko   return N;
8927310403eSTomasz Miąsko }
8937310403eSTomasz Miąsko 
8947310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
8957310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
8967310403eSTomasz Miąsko // "1_" encodes 2, etc.
8977310403eSTomasz Miąsko //
8987310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
parseBase62Number()8997310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
9007310403eSTomasz Miąsko   if (consumeIf('_'))
9017310403eSTomasz Miąsko     return 0;
9027310403eSTomasz Miąsko 
9037310403eSTomasz Miąsko   uint64_t Value = 0;
9047310403eSTomasz Miąsko 
9057310403eSTomasz Miąsko   while (true) {
9067310403eSTomasz Miąsko     uint64_t Digit;
9077310403eSTomasz Miąsko     char C = consume();
9087310403eSTomasz Miąsko 
9097310403eSTomasz Miąsko     if (C == '_') {
9107310403eSTomasz Miąsko       break;
9117310403eSTomasz Miąsko     } else if (isDigit(C)) {
9127310403eSTomasz Miąsko       Digit = C - '0';
9137310403eSTomasz Miąsko     } else if (isLower(C)) {
9147310403eSTomasz Miąsko       Digit = 10 + (C - 'a');
9157310403eSTomasz Miąsko     } else if (isUpper(C)) {
9167310403eSTomasz Miąsko       Digit = 10 + 26 + (C - 'A');
9177310403eSTomasz Miąsko     } else {
9187310403eSTomasz Miąsko       Error = true;
9197310403eSTomasz Miąsko       return 0;
9207310403eSTomasz Miąsko     }
9217310403eSTomasz Miąsko 
9227310403eSTomasz Miąsko     if (!mulAssign(Value, 62))
9237310403eSTomasz Miąsko       return 0;
9247310403eSTomasz Miąsko 
9257310403eSTomasz Miąsko     if (!addAssign(Value, Digit))
9267310403eSTomasz Miąsko       return 0;
9277310403eSTomasz Miąsko   }
9287310403eSTomasz Miąsko 
9297310403eSTomasz Miąsko   if (!addAssign(Value, 1))
9307310403eSTomasz Miąsko     return 0;
9317310403eSTomasz Miąsko 
9327310403eSTomasz Miąsko   return Value;
9337310403eSTomasz Miąsko }
9347310403eSTomasz Miąsko 
9357310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
9367310403eSTomasz Miąsko //
9377310403eSTomasz Miąsko // <decimal-number> = "0"
9387310403eSTomasz Miąsko //                  | <1-9> {<0-9>}
parseDecimalNumber()9397310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
9407310403eSTomasz Miąsko   char C = look();
9417310403eSTomasz Miąsko   if (!isDigit(C)) {
9427310403eSTomasz Miąsko     Error = true;
9437310403eSTomasz Miąsko     return 0;
9447310403eSTomasz Miąsko   }
9457310403eSTomasz Miąsko 
9467310403eSTomasz Miąsko   if (C == '0') {
9477310403eSTomasz Miąsko     consume();
9487310403eSTomasz Miąsko     return 0;
9497310403eSTomasz Miąsko   }
9507310403eSTomasz Miąsko 
9517310403eSTomasz Miąsko   uint64_t Value = 0;
9527310403eSTomasz Miąsko 
9537310403eSTomasz Miąsko   while (isDigit(look())) {
9547310403eSTomasz Miąsko     if (!mulAssign(Value, 10)) {
9557310403eSTomasz Miąsko       Error = true;
9567310403eSTomasz Miąsko       return 0;
9577310403eSTomasz Miąsko     }
9587310403eSTomasz Miąsko 
9597310403eSTomasz Miąsko     uint64_t D = consume() - '0';
9607310403eSTomasz Miąsko     if (!addAssign(Value, D))
9617310403eSTomasz Miąsko       return 0;
9627310403eSTomasz Miąsko   }
9637310403eSTomasz Miąsko 
9647310403eSTomasz Miąsko   return Value;
9657310403eSTomasz Miąsko }
966cd74dd17STomasz Miąsko 
967cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
968cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
969cd74dd17STomasz Miąsko // HexDigits.size() > 16.
970cd74dd17STomasz Miąsko //
971cd74dd17STomasz Miąsko // <hex-number> = "0_"
972cd74dd17STomasz Miąsko //              | <1-9a-f> {<0-9a-f>} "_"
parseHexNumber(StringView & HexDigits)973cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
974cd74dd17STomasz Miąsko   size_t Start = Position;
975cd74dd17STomasz Miąsko   uint64_t Value = 0;
976cd74dd17STomasz Miąsko 
977cd74dd17STomasz Miąsko   if (!isHexDigit(look()))
978cd74dd17STomasz Miąsko     Error = true;
979cd74dd17STomasz Miąsko 
980cd74dd17STomasz Miąsko   if (consumeIf('0')) {
981cd74dd17STomasz Miąsko     if (!consumeIf('_'))
982cd74dd17STomasz Miąsko       Error = true;
983cd74dd17STomasz Miąsko   } else {
984cd74dd17STomasz Miąsko     while (!Error && !consumeIf('_')) {
985cd74dd17STomasz Miąsko       char C = consume();
986cd74dd17STomasz Miąsko       Value *= 16;
987cd74dd17STomasz Miąsko       if (isDigit(C))
988cd74dd17STomasz Miąsko         Value += C - '0';
989cd74dd17STomasz Miąsko       else if ('a' <= C && C <= 'f')
990cd74dd17STomasz Miąsko         Value += 10 + (C - 'a');
991cd74dd17STomasz Miąsko       else
992cd74dd17STomasz Miąsko         Error = true;
993cd74dd17STomasz Miąsko     }
994cd74dd17STomasz Miąsko   }
995cd74dd17STomasz Miąsko 
996cd74dd17STomasz Miąsko   if (Error) {
997cd74dd17STomasz Miąsko     HexDigits = StringView();
998cd74dd17STomasz Miąsko     return 0;
999cd74dd17STomasz Miąsko   }
1000cd74dd17STomasz Miąsko 
1001cd74dd17STomasz Miąsko   size_t End = Position - 1;
1002cd74dd17STomasz Miąsko   assert(Start < End);
1003cd74dd17STomasz Miąsko   HexDigits = Input.substr(Start, End - Start);
1004cd74dd17STomasz Miąsko   return Value;
1005cd74dd17STomasz Miąsko }
1006a67a234eSTomasz Miąsko 
print(char C)10076cc6ada1STomasz Miąsko void Demangler::print(char C) {
10086cc6ada1STomasz Miąsko   if (Error || !Print)
10096cc6ada1STomasz Miąsko     return;
10106cc6ada1STomasz Miąsko 
10116cc6ada1STomasz Miąsko   Output += C;
10126cc6ada1STomasz Miąsko }
10136cc6ada1STomasz Miąsko 
print(StringView S)10146cc6ada1STomasz Miąsko void Demangler::print(StringView S) {
10156cc6ada1STomasz Miąsko   if (Error || !Print)
10166cc6ada1STomasz Miąsko     return;
10176cc6ada1STomasz Miąsko 
10186cc6ada1STomasz Miąsko   Output += S;
10196cc6ada1STomasz Miąsko }
10206cc6ada1STomasz Miąsko 
printDecimalNumber(uint64_t N)10216cc6ada1STomasz Miąsko void Demangler::printDecimalNumber(uint64_t N) {
10226cc6ada1STomasz Miąsko   if (Error || !Print)
10236cc6ada1STomasz Miąsko     return;
10246cc6ada1STomasz Miąsko 
10256cc6ada1STomasz Miąsko   Output << N;
10266cc6ada1STomasz Miąsko }
10276cc6ada1STomasz Miąsko 
1028a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
1029a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
1030a67a234eSTomasz Miąsko // bound by one of the enclosing binders.
printLifetime(uint64_t Index)1031a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) {
1032a67a234eSTomasz Miąsko   if (Index == 0) {
1033a67a234eSTomasz Miąsko     print("'_");
1034a67a234eSTomasz Miąsko     return;
1035a67a234eSTomasz Miąsko   }
1036a67a234eSTomasz Miąsko 
1037a67a234eSTomasz Miąsko   if (Index - 1 >= BoundLifetimes) {
1038a67a234eSTomasz Miąsko     Error = true;
1039a67a234eSTomasz Miąsko     return;
1040a67a234eSTomasz Miąsko   }
1041a67a234eSTomasz Miąsko 
1042a67a234eSTomasz Miąsko   uint64_t Depth = BoundLifetimes - Index;
1043a67a234eSTomasz Miąsko   print('\'');
1044a67a234eSTomasz Miąsko   if (Depth < 26) {
1045a67a234eSTomasz Miąsko     char C = 'a' + Depth;
1046a67a234eSTomasz Miąsko     print(C);
1047a67a234eSTomasz Miąsko   } else {
1048a67a234eSTomasz Miąsko     print('z');
1049a67a234eSTomasz Miąsko     printDecimalNumber(Depth - 26 + 1);
1050a67a234eSTomasz Miąsko   }
1051a67a234eSTomasz Miąsko }
10526cc6ada1STomasz Miąsko 
decodePunycodeDigit(char C,size_t & Value)1053c8c2b462STomasz Miąsko static inline bool decodePunycodeDigit(char C, size_t &Value) {
1054c8c2b462STomasz Miąsko   if (isLower(C)) {
1055c8c2b462STomasz Miąsko     Value = C - 'a';
1056c8c2b462STomasz Miąsko     return true;
1057c8c2b462STomasz Miąsko   }
1058c8c2b462STomasz Miąsko 
1059c8c2b462STomasz Miąsko   if (isDigit(C)) {
1060c8c2b462STomasz Miąsko     Value = 26 + (C - '0');
1061c8c2b462STomasz Miąsko     return true;
1062c8c2b462STomasz Miąsko   }
1063c8c2b462STomasz Miąsko 
1064c8c2b462STomasz Miąsko   return false;
1065c8c2b462STomasz Miąsko }
1066c8c2b462STomasz Miąsko 
removeNullBytes(OutputBuffer & Output,size_t StartIdx)10672e97236aSLuís Ferreira static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) {
1068c8c2b462STomasz Miąsko   char *Buffer = Output.getBuffer();
1069c8c2b462STomasz Miąsko   char *Start = Buffer + StartIdx;
1070c8c2b462STomasz Miąsko   char *End = Buffer + Output.getCurrentPosition();
1071c8c2b462STomasz Miąsko   Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer);
1072c8c2b462STomasz Miąsko }
1073c8c2b462STomasz Miąsko 
1074c8c2b462STomasz Miąsko // Encodes code point as UTF-8 and stores results in Output. Returns false if
1075c8c2b462STomasz Miąsko // CodePoint is not a valid unicode scalar value.
encodeUTF8(size_t CodePoint,char * Output)1076c8c2b462STomasz Miąsko static inline bool encodeUTF8(size_t CodePoint, char *Output) {
1077c8c2b462STomasz Miąsko   if (0xD800 <= CodePoint && CodePoint <= 0xDFFF)
1078c8c2b462STomasz Miąsko     return false;
1079c8c2b462STomasz Miąsko 
1080c8c2b462STomasz Miąsko   if (CodePoint <= 0x7F) {
1081c8c2b462STomasz Miąsko     Output[0] = CodePoint;
1082c8c2b462STomasz Miąsko     return true;
1083c8c2b462STomasz Miąsko   }
1084c8c2b462STomasz Miąsko 
1085c8c2b462STomasz Miąsko   if (CodePoint <= 0x7FF) {
1086c8c2b462STomasz Miąsko     Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F);
1087c8c2b462STomasz Miąsko     Output[1] = 0x80 | (CodePoint & 0x3F);
1088c8c2b462STomasz Miąsko     return true;
1089c8c2b462STomasz Miąsko   }
1090c8c2b462STomasz Miąsko 
1091c8c2b462STomasz Miąsko   if (CodePoint <= 0xFFFF) {
1092c8c2b462STomasz Miąsko     Output[0] = 0xE0 | (CodePoint >> 12);
1093c8c2b462STomasz Miąsko     Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F);
1094c8c2b462STomasz Miąsko     Output[2] = 0x80 | (CodePoint & 0x3F);
1095c8c2b462STomasz Miąsko     return true;
1096c8c2b462STomasz Miąsko   }
1097c8c2b462STomasz Miąsko 
1098c8c2b462STomasz Miąsko   if (CodePoint <= 0x10FFFF) {
1099c8c2b462STomasz Miąsko     Output[0] = 0xF0 | (CodePoint >> 18);
1100c8c2b462STomasz Miąsko     Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F);
1101c8c2b462STomasz Miąsko     Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F);
1102c8c2b462STomasz Miąsko     Output[3] = 0x80 | (CodePoint & 0x3F);
1103c8c2b462STomasz Miąsko     return true;
1104c8c2b462STomasz Miąsko   }
1105c8c2b462STomasz Miąsko 
1106c8c2b462STomasz Miąsko   return false;
1107c8c2b462STomasz Miąsko }
1108c8c2b462STomasz Miąsko 
1109c8c2b462STomasz Miąsko // Decodes string encoded using punycode and appends results to Output.
1110c8c2b462STomasz Miąsko // Returns true if decoding was successful.
decodePunycode(StringView Input,OutputBuffer & Output)11112e97236aSLuís Ferreira static bool decodePunycode(StringView Input, OutputBuffer &Output) {
1112c8c2b462STomasz Miąsko   size_t OutputSize = Output.getCurrentPosition();
1113c8c2b462STomasz Miąsko   size_t InputIdx = 0;
1114c8c2b462STomasz Miąsko 
1115c8c2b462STomasz Miąsko   // Rust uses an underscore as a delimiter.
1116c8c2b462STomasz Miąsko   size_t DelimiterPos = StringView::npos;
1117c8c2b462STomasz Miąsko   for (size_t I = 0; I != Input.size(); ++I)
1118c8c2b462STomasz Miąsko     if (Input[I] == '_')
1119c8c2b462STomasz Miąsko       DelimiterPos = I;
1120c8c2b462STomasz Miąsko 
1121c8c2b462STomasz Miąsko   if (DelimiterPos != StringView::npos) {
1122c8c2b462STomasz Miąsko     // Copy basic code points before the last delimiter to the output.
1123c8c2b462STomasz Miąsko     for (; InputIdx != DelimiterPos; ++InputIdx) {
1124c8c2b462STomasz Miąsko       char C = Input[InputIdx];
1125c8c2b462STomasz Miąsko       if (!isValid(C))
1126c8c2b462STomasz Miąsko         return false;
1127c8c2b462STomasz Miąsko       // Code points are padded with zeros while decoding is in progress.
1128c8c2b462STomasz Miąsko       char UTF8[4] = {C};
1129c8c2b462STomasz Miąsko       Output += StringView(UTF8, UTF8 + 4);
1130c8c2b462STomasz Miąsko     }
1131c8c2b462STomasz Miąsko     // Skip over the delimiter.
1132c8c2b462STomasz Miąsko     ++InputIdx;
1133c8c2b462STomasz Miąsko   }
1134c8c2b462STomasz Miąsko 
1135c8c2b462STomasz Miąsko   size_t Base = 36;
1136c8c2b462STomasz Miąsko   size_t Skew = 38;
1137c8c2b462STomasz Miąsko   size_t Bias = 72;
1138c8c2b462STomasz Miąsko   size_t N = 0x80;
1139c8c2b462STomasz Miąsko   size_t TMin = 1;
1140c8c2b462STomasz Miąsko   size_t TMax = 26;
1141c8c2b462STomasz Miąsko   size_t Damp = 700;
1142c8c2b462STomasz Miąsko 
1143c8c2b462STomasz Miąsko   auto Adapt = [&](size_t Delta, size_t NumPoints) {
1144c8c2b462STomasz Miąsko     Delta /= Damp;
1145c8c2b462STomasz Miąsko     Delta += Delta / NumPoints;
1146c8c2b462STomasz Miąsko     Damp = 2;
1147c8c2b462STomasz Miąsko 
1148c8c2b462STomasz Miąsko     size_t K = 0;
1149c8c2b462STomasz Miąsko     while (Delta > (Base - TMin) * TMax / 2) {
1150c8c2b462STomasz Miąsko       Delta /= Base - TMin;
1151c8c2b462STomasz Miąsko       K += Base;
1152c8c2b462STomasz Miąsko     }
1153c8c2b462STomasz Miąsko     return K + (((Base - TMin + 1) * Delta) / (Delta + Skew));
1154c8c2b462STomasz Miąsko   };
1155c8c2b462STomasz Miąsko 
1156c8c2b462STomasz Miąsko   // Main decoding loop.
1157c8c2b462STomasz Miąsko   for (size_t I = 0; InputIdx != Input.size(); I += 1) {
1158c8c2b462STomasz Miąsko     size_t OldI = I;
1159c8c2b462STomasz Miąsko     size_t W = 1;
1160c8c2b462STomasz Miąsko     size_t Max = std::numeric_limits<size_t>::max();
1161c8c2b462STomasz Miąsko     for (size_t K = Base; true; K += Base) {
1162c8c2b462STomasz Miąsko       if (InputIdx == Input.size())
1163c8c2b462STomasz Miąsko         return false;
1164c8c2b462STomasz Miąsko       char C = Input[InputIdx++];
1165c8c2b462STomasz Miąsko       size_t Digit = 0;
1166c8c2b462STomasz Miąsko       if (!decodePunycodeDigit(C, Digit))
1167c8c2b462STomasz Miąsko         return false;
1168c8c2b462STomasz Miąsko 
1169c8c2b462STomasz Miąsko       if (Digit > (Max - I) / W)
1170c8c2b462STomasz Miąsko         return false;
1171c8c2b462STomasz Miąsko       I += Digit * W;
1172c8c2b462STomasz Miąsko 
1173c8c2b462STomasz Miąsko       size_t T;
1174c8c2b462STomasz Miąsko       if (K <= Bias)
1175c8c2b462STomasz Miąsko         T = TMin;
1176c8c2b462STomasz Miąsko       else if (K >= Bias + TMax)
1177c8c2b462STomasz Miąsko         T = TMax;
1178c8c2b462STomasz Miąsko       else
1179c8c2b462STomasz Miąsko         T = K - Bias;
1180c8c2b462STomasz Miąsko 
1181c8c2b462STomasz Miąsko       if (Digit < T)
1182c8c2b462STomasz Miąsko         break;
1183c8c2b462STomasz Miąsko 
1184c8c2b462STomasz Miąsko       if (W > Max / (Base - T))
1185c8c2b462STomasz Miąsko         return false;
1186c8c2b462STomasz Miąsko       W *= (Base - T);
1187c8c2b462STomasz Miąsko     }
1188c8c2b462STomasz Miąsko     size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1;
1189c8c2b462STomasz Miąsko     Bias = Adapt(I - OldI, NumPoints);
1190c8c2b462STomasz Miąsko 
1191c8c2b462STomasz Miąsko     if (I / NumPoints > Max - N)
1192c8c2b462STomasz Miąsko       return false;
1193c8c2b462STomasz Miąsko     N += I / NumPoints;
1194c8c2b462STomasz Miąsko     I = I % NumPoints;
1195c8c2b462STomasz Miąsko 
1196c8c2b462STomasz Miąsko     // Insert N at position I in the output.
1197c8c2b462STomasz Miąsko     char UTF8[4] = {};
1198c8c2b462STomasz Miąsko     if (!encodeUTF8(N, UTF8))
1199c8c2b462STomasz Miąsko       return false;
1200c8c2b462STomasz Miąsko     Output.insert(OutputSize + I * 4, UTF8, 4);
1201c8c2b462STomasz Miąsko   }
1202c8c2b462STomasz Miąsko 
1203c8c2b462STomasz Miąsko   removeNullBytes(Output, OutputSize);
1204c8c2b462STomasz Miąsko   return true;
1205c8c2b462STomasz Miąsko }
1206c8c2b462STomasz Miąsko 
printIdentifier(Identifier Ident)1207c8c2b462STomasz Miąsko void Demangler::printIdentifier(Identifier Ident) {
1208c8c2b462STomasz Miąsko   if (Error || !Print)
1209c8c2b462STomasz Miąsko     return;
1210c8c2b462STomasz Miąsko 
1211c8c2b462STomasz Miąsko   if (Ident.Punycode) {
1212c8c2b462STomasz Miąsko     if (!decodePunycode(Ident.Name, Output))
1213c8c2b462STomasz Miąsko       Error = true;
1214c8c2b462STomasz Miąsko   } else {
1215c8c2b462STomasz Miąsko     print(Ident.Name);
1216c8c2b462STomasz Miąsko   }
1217c8c2b462STomasz Miąsko }
1218c8c2b462STomasz Miąsko 
look() const12196cc6ada1STomasz Miąsko char Demangler::look() const {
12206cc6ada1STomasz Miąsko   if (Error || Position >= Input.size())
12216cc6ada1STomasz Miąsko     return 0;
12226cc6ada1STomasz Miąsko 
12236cc6ada1STomasz Miąsko   return Input[Position];
12246cc6ada1STomasz Miąsko }
12256cc6ada1STomasz Miąsko 
consume()12266cc6ada1STomasz Miąsko char Demangler::consume() {
12276cc6ada1STomasz Miąsko   if (Error || Position >= Input.size()) {
12286cc6ada1STomasz Miąsko     Error = true;
12296cc6ada1STomasz Miąsko     return 0;
12306cc6ada1STomasz Miąsko   }
12316cc6ada1STomasz Miąsko 
12326cc6ada1STomasz Miąsko   return Input[Position++];
12336cc6ada1STomasz Miąsko }
12346cc6ada1STomasz Miąsko 
consumeIf(char Prefix)12356cc6ada1STomasz Miąsko bool Demangler::consumeIf(char Prefix) {
12366cc6ada1STomasz Miąsko   if (Error || Position >= Input.size() || Input[Position] != Prefix)
12376cc6ada1STomasz Miąsko     return false;
12386cc6ada1STomasz Miąsko 
12396cc6ada1STomasz Miąsko   Position += 1;
12406cc6ada1STomasz Miąsko   return true;
12416cc6ada1STomasz Miąsko }
12426cc6ada1STomasz Miąsko 
12436cc6ada1STomasz Miąsko /// Computes A + B. When computation wraps around sets the error and returns
12446cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
addAssign(uint64_t & A,uint64_t B)12456cc6ada1STomasz Miąsko bool Demangler::addAssign(uint64_t &A, uint64_t B) {
12466cc6ada1STomasz Miąsko   if (A > std::numeric_limits<uint64_t>::max() - B) {
12476cc6ada1STomasz Miąsko     Error = true;
12486cc6ada1STomasz Miąsko     return false;
12496cc6ada1STomasz Miąsko   }
12506cc6ada1STomasz Miąsko 
12516cc6ada1STomasz Miąsko   A += B;
12526cc6ada1STomasz Miąsko   return true;
12536cc6ada1STomasz Miąsko }
12546cc6ada1STomasz Miąsko 
12556cc6ada1STomasz Miąsko /// Computes A * B. When computation wraps around sets the error and returns
12566cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
mulAssign(uint64_t & A,uint64_t B)12576cc6ada1STomasz Miąsko bool Demangler::mulAssign(uint64_t &A, uint64_t B) {
12586cc6ada1STomasz Miąsko   if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) {
12596cc6ada1STomasz Miąsko     Error = true;
12606cc6ada1STomasz Miąsko     return false;
12616cc6ada1STomasz Miąsko   }
12626cc6ada1STomasz Miąsko 
12636cc6ada1STomasz Miąsko   A *= B;
12646cc6ada1STomasz Miąsko   return true;
12656cc6ada1STomasz Miąsko }
1266