xref: /llvm-project/llvm/lib/Demangle/RustDemangle.cpp (revision 9ae24fca2522c70eaff6c3e9c5ea89675db7c213)
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"
157c59e800SNick Desaulniers #include "llvm/Demangle/StringViewExtras.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>
2312d967c9SNick Desaulniers #include <string_view>
247310403eSTomasz Miąsko 
257310403eSTomasz Miąsko using namespace llvm;
266cc6ada1STomasz Miąsko 
272e97236aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer;
2851f6caf2SNathan Sidwell using llvm::itanium_demangle::ScopedOverride;
2912d967c9SNick Desaulniers using llvm::itanium_demangle::starts_with;
306cc6ada1STomasz Miąsko 
316cc6ada1STomasz Miąsko namespace {
326cc6ada1STomasz Miąsko 
336cc6ada1STomasz Miąsko struct Identifier {
347c59e800SNick Desaulniers   std::string_view Name;
356cc6ada1STomasz Miąsko   bool Punycode;
366cc6ada1STomasz Miąsko 
376cc6ada1STomasz Miąsko   bool empty() const { return Name.empty(); }
386cc6ada1STomasz Miąsko };
396cc6ada1STomasz Miąsko 
406cc6ada1STomasz Miąsko enum class BasicType {
416cc6ada1STomasz Miąsko   Bool,
426cc6ada1STomasz Miąsko   Char,
436cc6ada1STomasz Miąsko   I8,
446cc6ada1STomasz Miąsko   I16,
456cc6ada1STomasz Miąsko   I32,
466cc6ada1STomasz Miąsko   I64,
476cc6ada1STomasz Miąsko   I128,
486cc6ada1STomasz Miąsko   ISize,
496cc6ada1STomasz Miąsko   U8,
506cc6ada1STomasz Miąsko   U16,
516cc6ada1STomasz Miąsko   U32,
526cc6ada1STomasz Miąsko   U64,
536cc6ada1STomasz Miąsko   U128,
546cc6ada1STomasz Miąsko   USize,
556cc6ada1STomasz Miąsko   F32,
566cc6ada1STomasz Miąsko   F64,
576cc6ada1STomasz Miąsko   Str,
586cc6ada1STomasz Miąsko   Placeholder,
596cc6ada1STomasz Miąsko   Unit,
606cc6ada1STomasz Miąsko   Variadic,
616cc6ada1STomasz Miąsko   Never,
626cc6ada1STomasz Miąsko };
636cc6ada1STomasz Miąsko 
646cc6ada1STomasz Miąsko enum class IsInType {
656cc6ada1STomasz Miąsko   No,
666cc6ada1STomasz Miąsko   Yes,
676cc6ada1STomasz Miąsko };
686cc6ada1STomasz Miąsko 
696cc6ada1STomasz Miąsko enum class LeaveGenericsOpen {
706cc6ada1STomasz Miąsko   No,
716cc6ada1STomasz Miąsko   Yes,
726cc6ada1STomasz Miąsko };
736cc6ada1STomasz Miąsko 
746cc6ada1STomasz Miąsko class Demangler {
756cc6ada1STomasz Miąsko   // Maximum recursion level. Used to avoid stack overflow.
766cc6ada1STomasz Miąsko   size_t MaxRecursionLevel;
776cc6ada1STomasz Miąsko   // Current recursion level.
786cc6ada1STomasz Miąsko   size_t RecursionLevel;
796cc6ada1STomasz Miąsko   size_t BoundLifetimes;
806cc6ada1STomasz Miąsko   // Input string that is being demangled with "_R" prefix removed.
817c59e800SNick Desaulniers   std::string_view Input;
826cc6ada1STomasz Miąsko   // Position in the input string.
836cc6ada1STomasz Miąsko   size_t Position;
846cc6ada1STomasz Miąsko   // When true, print methods append the output to the stream.
856cc6ada1STomasz Miąsko   // When false, the output is suppressed.
866cc6ada1STomasz Miąsko   bool Print;
876cc6ada1STomasz Miąsko   // True if an error occurred.
886cc6ada1STomasz Miąsko   bool Error;
896cc6ada1STomasz Miąsko 
906cc6ada1STomasz Miąsko public:
916cc6ada1STomasz Miąsko   // Demangled output.
922e97236aSLuís Ferreira   OutputBuffer Output;
936cc6ada1STomasz Miąsko 
946cc6ada1STomasz Miąsko   Demangler(size_t MaxRecursionLevel = 500);
956cc6ada1STomasz Miąsko 
967c59e800SNick Desaulniers   bool demangle(std::string_view MangledName);
976cc6ada1STomasz Miąsko 
986cc6ada1STomasz Miąsko private:
996cc6ada1STomasz Miąsko   bool demanglePath(IsInType Type,
1006cc6ada1STomasz Miąsko                     LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No);
1016cc6ada1STomasz Miąsko   void demangleImplPath(IsInType InType);
1026cc6ada1STomasz Miąsko   void demangleGenericArg();
1036cc6ada1STomasz Miąsko   void demangleType();
1046cc6ada1STomasz Miąsko   void demangleFnSig();
1056cc6ada1STomasz Miąsko   void demangleDynBounds();
1066cc6ada1STomasz Miąsko   void demangleDynTrait();
1076cc6ada1STomasz Miąsko   void demangleOptionalBinder();
1086cc6ada1STomasz Miąsko   void demangleConst();
1096cc6ada1STomasz Miąsko   void demangleConstInt();
1106cc6ada1STomasz Miąsko   void demangleConstBool();
1116cc6ada1STomasz Miąsko   void demangleConstChar();
1126cc6ada1STomasz Miąsko 
1136cc6ada1STomasz Miąsko   template <typename Callable> void demangleBackref(Callable Demangler) {
1146cc6ada1STomasz Miąsko     uint64_t Backref = parseBase62Number();
1156cc6ada1STomasz Miąsko     if (Error || Backref >= Position) {
1166cc6ada1STomasz Miąsko       Error = true;
1176cc6ada1STomasz Miąsko       return;
1186cc6ada1STomasz Miąsko     }
1196cc6ada1STomasz Miąsko 
1206cc6ada1STomasz Miąsko     if (!Print)
1216cc6ada1STomasz Miąsko       return;
1226cc6ada1STomasz Miąsko 
12351f6caf2SNathan Sidwell     ScopedOverride<size_t> SavePosition(Position, Position);
1246cc6ada1STomasz Miąsko     Position = Backref;
1256cc6ada1STomasz Miąsko     Demangler();
1266cc6ada1STomasz Miąsko   }
1276cc6ada1STomasz Miąsko 
1286cc6ada1STomasz Miąsko   Identifier parseIdentifier();
1296cc6ada1STomasz Miąsko   uint64_t parseOptionalBase62Number(char Tag);
1306cc6ada1STomasz Miąsko   uint64_t parseBase62Number();
1316cc6ada1STomasz Miąsko   uint64_t parseDecimalNumber();
1327c59e800SNick Desaulniers   uint64_t parseHexNumber(std::string_view &HexDigits);
1336cc6ada1STomasz Miąsko 
1346cc6ada1STomasz Miąsko   void print(char C);
1357c59e800SNick Desaulniers   void print(std::string_view S);
1366cc6ada1STomasz Miąsko   void printDecimalNumber(uint64_t N);
1376cc6ada1STomasz Miąsko   void printBasicType(BasicType);
1386cc6ada1STomasz Miąsko   void printLifetime(uint64_t Index);
139c8c2b462STomasz Miąsko   void printIdentifier(Identifier Ident);
1406cc6ada1STomasz Miąsko 
1416cc6ada1STomasz Miąsko   char look() const;
1426cc6ada1STomasz Miąsko   char consume();
1436cc6ada1STomasz Miąsko   bool consumeIf(char Prefix);
1446cc6ada1STomasz Miąsko 
1456cc6ada1STomasz Miąsko   bool addAssign(uint64_t &A, uint64_t B);
1466cc6ada1STomasz Miąsko   bool mulAssign(uint64_t &A, uint64_t B);
1476cc6ada1STomasz Miąsko };
1486cc6ada1STomasz Miąsko 
1496cc6ada1STomasz Miąsko } // namespace
1507310403eSTomasz Miąsko 
15112d967c9SNick Desaulniers char *llvm::rustDemangle(std::string_view MangledName) {
1527310403eSTomasz Miąsko   // Return early if mangled name doesn't look like a Rust symbol.
15312d967c9SNick Desaulniers   if (MangledName.empty() || !starts_with(MangledName, "_R"))
1547310403eSTomasz Miąsko     return nullptr;
1557310403eSTomasz Miąsko 
1567310403eSTomasz Miąsko   Demangler D;
15712d967c9SNick Desaulniers   if (!D.demangle(MangledName)) {
1587310403eSTomasz Miąsko     std::free(D.Output.getBuffer());
1597310403eSTomasz Miąsko     return nullptr;
1607310403eSTomasz Miąsko   }
1617310403eSTomasz Miąsko 
1627310403eSTomasz Miąsko   D.Output += '\0';
1637310403eSTomasz Miąsko 
164201c4b9cSNathan Sidwell   return D.Output.getBuffer();
1657310403eSTomasz Miąsko }
1667310403eSTomasz Miąsko 
1677310403eSTomasz Miąsko Demangler::Demangler(size_t MaxRecursionLevel)
1687310403eSTomasz Miąsko     : MaxRecursionLevel(MaxRecursionLevel) {}
1697310403eSTomasz Miąsko 
1707310403eSTomasz Miąsko static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
1717310403eSTomasz Miąsko 
172cd74dd17STomasz Miąsko static inline bool isHexDigit(const char C) {
173cd74dd17STomasz Miąsko   return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
174cd74dd17STomasz Miąsko }
175cd74dd17STomasz Miąsko 
1767310403eSTomasz Miąsko static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
1777310403eSTomasz Miąsko 
1787310403eSTomasz Miąsko static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
1797310403eSTomasz Miąsko 
1807310403eSTomasz Miąsko /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
1817310403eSTomasz Miąsko static inline bool isValid(const char C) {
1827310403eSTomasz Miąsko   return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
1837310403eSTomasz Miąsko }
1847310403eSTomasz Miąsko 
1857310403eSTomasz Miąsko // Demangles Rust v0 mangled symbol. Returns true when successful, and false
1867310403eSTomasz Miąsko // otherwise. The demangled symbol is stored in Output field. It is
1877310403eSTomasz Miąsko // responsibility of the caller to free the memory behind the output stream.
1887310403eSTomasz Miąsko //
1897310403eSTomasz Miąsko // <symbol-name> = "_R" <path> [<instantiating-crate>]
1907c59e800SNick Desaulniers bool Demangler::demangle(std::string_view Mangled) {
1917310403eSTomasz Miąsko   Position = 0;
1927310403eSTomasz Miąsko   Error = false;
193f0f2a8b2STomasz Miąsko   Print = true;
1947310403eSTomasz Miąsko   RecursionLevel = 0;
195a67a234eSTomasz Miąsko   BoundLifetimes = 0;
1967310403eSTomasz Miąsko 
19712d967c9SNick Desaulniers   if (!starts_with(Mangled, "_R")) {
1987310403eSTomasz Miąsko     Error = true;
1997310403eSTomasz Miąsko     return false;
2007310403eSTomasz Miąsko   }
2015e53e1bbSNick Desaulniers   Mangled.remove_prefix(2);
2022a5bb9c8STomasz Miąsko   size_t Dot = Mangled.find('.');
2037c59e800SNick Desaulniers   Input = Dot == std::string_view::npos ? Mangled : Mangled.substr(0, Dot);
2047310403eSTomasz Miąsko 
2056cc6ada1STomasz Miąsko   demanglePath(IsInType::No);
2067310403eSTomasz Miąsko 
20743929cccSTomasz Miąsko   if (Position != Input.size()) {
20851f6caf2SNathan Sidwell     ScopedOverride<bool> SavePrint(Print, false);
2096cc6ada1STomasz Miąsko     demanglePath(IsInType::No);
21043929cccSTomasz Miąsko   }
2117310403eSTomasz Miąsko 
2127310403eSTomasz Miąsko   if (Position != Input.size())
2137310403eSTomasz Miąsko     Error = true;
2147310403eSTomasz Miąsko 
2157c59e800SNick Desaulniers   if (Dot != std::string_view::npos) {
2162a5bb9c8STomasz Miąsko     print(" (");
217c8144eeaSNick Desaulniers     print(Mangled.substr(Dot));
2182a5bb9c8STomasz Miąsko     print(")");
2192a5bb9c8STomasz Miąsko   }
2202a5bb9c8STomasz Miąsko 
2217310403eSTomasz Miąsko   return !Error;
2227310403eSTomasz Miąsko }
2237310403eSTomasz Miąsko 
224619a65e5STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type. When
225619a65e5STomasz Miąsko // LeaveOpen is true, a closing `>` after generic arguments is omitted from the
226619a65e5STomasz Miąsko // output. Return value indicates whether generics arguments have been left
227619a65e5STomasz Miąsko // open.
22806833297STomasz Miąsko //
2297310403eSTomasz Miąsko // <path> = "C" <identifier>               // crate root
2307310403eSTomasz Miąsko //        | "M" <impl-path> <type>         // <T> (inherent impl)
2317310403eSTomasz Miąsko //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
2327310403eSTomasz Miąsko //        | "Y" <type> <path>              // <T as Trait> (trait definition)
2337310403eSTomasz Miąsko //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
2347310403eSTomasz Miąsko //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
2357310403eSTomasz Miąsko //        | <backref>
2367310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
2377310403eSTomasz Miąsko // <ns> = "C"      // closure
2387310403eSTomasz Miąsko //      | "S"      // shim
2397310403eSTomasz Miąsko //      | <A-Z>    // other special namespaces
2407310403eSTomasz Miąsko //      | <a-z>    // internal namespaces
2416cc6ada1STomasz Miąsko bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) {
2427310403eSTomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
2437310403eSTomasz Miąsko     Error = true;
244619a65e5STomasz Miąsko     return false;
2457310403eSTomasz Miąsko   }
24651f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
2477310403eSTomasz Miąsko 
2487310403eSTomasz Miąsko   switch (consume()) {
2497310403eSTomasz Miąsko   case 'C': {
2507310403eSTomasz Miąsko     parseOptionalBase62Number('s');
251c8c2b462STomasz Miąsko     printIdentifier(parseIdentifier());
2527310403eSTomasz Miąsko     break;
2537310403eSTomasz Miąsko   }
254f0f2a8b2STomasz Miąsko   case 'M': {
25506833297STomasz Miąsko     demangleImplPath(InType);
256f0f2a8b2STomasz Miąsko     print("<");
257f0f2a8b2STomasz Miąsko     demangleType();
258f0f2a8b2STomasz Miąsko     print(">");
259f0f2a8b2STomasz Miąsko     break;
260f0f2a8b2STomasz Miąsko   }
2619fa13800STomasz Miąsko   case 'X': {
26206833297STomasz Miąsko     demangleImplPath(InType);
2639fa13800STomasz Miąsko     print("<");
2649fa13800STomasz Miąsko     demangleType();
2659fa13800STomasz Miąsko     print(" as ");
2666cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
2679fa13800STomasz Miąsko     print(">");
2689fa13800STomasz Miąsko     break;
2699fa13800STomasz Miąsko   }
270f933f7fbSTomasz Miąsko   case 'Y': {
271f933f7fbSTomasz Miąsko     print("<");
272f933f7fbSTomasz Miąsko     demangleType();
273f933f7fbSTomasz Miąsko     print(" as ");
2746cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
275f933f7fbSTomasz Miąsko     print(">");
276f933f7fbSTomasz Miąsko     break;
277f933f7fbSTomasz Miąsko   }
2787310403eSTomasz Miąsko   case 'N': {
2797310403eSTomasz Miąsko     char NS = consume();
2807310403eSTomasz Miąsko     if (!isLower(NS) && !isUpper(NS)) {
2817310403eSTomasz Miąsko       Error = true;
2827310403eSTomasz Miąsko       break;
2837310403eSTomasz Miąsko     }
28406833297STomasz Miąsko     demanglePath(InType);
2857310403eSTomasz Miąsko 
28678e94915STomasz Miąsko     uint64_t Disambiguator = parseOptionalBase62Number('s');
2877310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
2887310403eSTomasz Miąsko 
28978e94915STomasz Miąsko     if (isUpper(NS)) {
29078e94915STomasz Miąsko       // Special namespaces
29178e94915STomasz Miąsko       print("::{");
29278e94915STomasz Miąsko       if (NS == 'C')
29378e94915STomasz Miąsko         print("closure");
29478e94915STomasz Miąsko       else if (NS == 'S')
29578e94915STomasz Miąsko         print("shim");
29678e94915STomasz Miąsko       else
29778e94915STomasz Miąsko         print(NS);
2987310403eSTomasz Miąsko       if (!Ident.empty()) {
29978e94915STomasz Miąsko         print(":");
300c8c2b462STomasz Miąsko         printIdentifier(Ident);
30178e94915STomasz Miąsko       }
30278e94915STomasz Miąsko       print('#');
30378e94915STomasz Miąsko       printDecimalNumber(Disambiguator);
30478e94915STomasz Miąsko       print('}');
30578e94915STomasz Miąsko     } else {
30678e94915STomasz Miąsko       // Implementation internal namespaces.
30778e94915STomasz Miąsko       if (!Ident.empty()) {
3087310403eSTomasz Miąsko         print("::");
309c8c2b462STomasz Miąsko         printIdentifier(Ident);
3107310403eSTomasz Miąsko       }
31178e94915STomasz Miąsko     }
3127310403eSTomasz Miąsko     break;
3137310403eSTomasz Miąsko   }
3142961f863STomasz Miąsko   case 'I': {
31506833297STomasz Miąsko     demanglePath(InType);
31606833297STomasz Miąsko     // Omit "::" when in a type, where it is optional.
3176cc6ada1STomasz Miąsko     if (InType == IsInType::No)
31806833297STomasz Miąsko       print("::");
31906833297STomasz Miąsko     print("<");
3202961f863STomasz Miąsko     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
3212961f863STomasz Miąsko       if (I > 0)
3222961f863STomasz Miąsko         print(", ");
3232961f863STomasz Miąsko       demangleGenericArg();
3242961f863STomasz Miąsko     }
3256cc6ada1STomasz Miąsko     if (LeaveOpen == LeaveGenericsOpen::Yes)
326619a65e5STomasz Miąsko       return true;
327619a65e5STomasz Miąsko     else
3282961f863STomasz Miąsko       print(">");
3292961f863STomasz Miąsko     break;
3302961f863STomasz Miąsko   }
33182b7e822STomasz Miąsko   case 'B': {
33282b7e822STomasz Miąsko     bool IsOpen = false;
33382b7e822STomasz Miąsko     demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
33482b7e822STomasz Miąsko     return IsOpen;
33582b7e822STomasz Miąsko   }
3367310403eSTomasz Miąsko   default:
3377310403eSTomasz Miąsko     Error = true;
3387310403eSTomasz Miąsko     break;
3397310403eSTomasz Miąsko   }
340619a65e5STomasz Miąsko 
341619a65e5STomasz Miąsko   return false;
3427310403eSTomasz Miąsko }
3437310403eSTomasz Miąsko 
344f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path>
345f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number>
3466cc6ada1STomasz Miąsko void Demangler::demangleImplPath(IsInType InType) {
34751f6caf2SNathan Sidwell   ScopedOverride<bool> SavePrint(Print, false);
348f0f2a8b2STomasz Miąsko   parseOptionalBase62Number('s');
34906833297STomasz Miąsko   demanglePath(InType);
350f0f2a8b2STomasz Miąsko }
351f0f2a8b2STomasz Miąsko 
3522961f863STomasz Miąsko // <generic-arg> = <lifetime>
3532961f863STomasz Miąsko //               | <type>
3542961f863STomasz Miąsko //               | "K" <const>
3552961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
3562961f863STomasz Miąsko void Demangler::demangleGenericArg() {
357a67a234eSTomasz Miąsko   if (consumeIf('L'))
358a67a234eSTomasz Miąsko     printLifetime(parseBase62Number());
359a67a234eSTomasz Miąsko   else if (consumeIf('K'))
360cd74dd17STomasz Miąsko     demangleConst();
361cd74dd17STomasz Miąsko   else
3622961f863STomasz Miąsko     demangleType();
3632961f863STomasz Miąsko }
3642961f863STomasz Miąsko 
3652961f863STomasz Miąsko // <basic-type> = "a"      // i8
3662961f863STomasz Miąsko //              | "b"      // bool
3672961f863STomasz Miąsko //              | "c"      // char
3682961f863STomasz Miąsko //              | "d"      // f64
3692961f863STomasz Miąsko //              | "e"      // str
3702961f863STomasz Miąsko //              | "f"      // f32
3712961f863STomasz Miąsko //              | "h"      // u8
3722961f863STomasz Miąsko //              | "i"      // isize
3732961f863STomasz Miąsko //              | "j"      // usize
3742961f863STomasz Miąsko //              | "l"      // i32
3752961f863STomasz Miąsko //              | "m"      // u32
3762961f863STomasz Miąsko //              | "n"      // i128
3772961f863STomasz Miąsko //              | "o"      // u128
3782961f863STomasz Miąsko //              | "s"      // i16
3792961f863STomasz Miąsko //              | "t"      // u16
3802961f863STomasz Miąsko //              | "u"      // ()
3812961f863STomasz Miąsko //              | "v"      // ...
3822961f863STomasz Miąsko //              | "x"      // i64
3832961f863STomasz Miąsko //              | "y"      // u64
3842961f863STomasz Miąsko //              | "z"      // !
3852961f863STomasz Miąsko //              | "p"      // placeholder (e.g. for generic params), shown as _
386cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
387cd74dd17STomasz Miąsko   switch (C) {
388cd74dd17STomasz Miąsko   case 'a':
389cd74dd17STomasz Miąsko     Type = BasicType::I8;
390cd74dd17STomasz Miąsko     return true;
391cd74dd17STomasz Miąsko   case 'b':
392cd74dd17STomasz Miąsko     Type = BasicType::Bool;
393cd74dd17STomasz Miąsko     return true;
394cd74dd17STomasz Miąsko   case 'c':
395cd74dd17STomasz Miąsko     Type = BasicType::Char;
396cd74dd17STomasz Miąsko     return true;
397cd74dd17STomasz Miąsko   case 'd':
398cd74dd17STomasz Miąsko     Type = BasicType::F64;
399cd74dd17STomasz Miąsko     return true;
400cd74dd17STomasz Miąsko   case 'e':
401cd74dd17STomasz Miąsko     Type = BasicType::Str;
402cd74dd17STomasz Miąsko     return true;
403cd74dd17STomasz Miąsko   case 'f':
404cd74dd17STomasz Miąsko     Type = BasicType::F32;
405cd74dd17STomasz Miąsko     return true;
406cd74dd17STomasz Miąsko   case 'h':
407cd74dd17STomasz Miąsko     Type = BasicType::U8;
408cd74dd17STomasz Miąsko     return true;
409cd74dd17STomasz Miąsko   case 'i':
410cd74dd17STomasz Miąsko     Type = BasicType::ISize;
411cd74dd17STomasz Miąsko     return true;
412cd74dd17STomasz Miąsko   case 'j':
413cd74dd17STomasz Miąsko     Type = BasicType::USize;
414cd74dd17STomasz Miąsko     return true;
415cd74dd17STomasz Miąsko   case 'l':
416cd74dd17STomasz Miąsko     Type = BasicType::I32;
417cd74dd17STomasz Miąsko     return true;
418cd74dd17STomasz Miąsko   case 'm':
419cd74dd17STomasz Miąsko     Type = BasicType::U32;
420cd74dd17STomasz Miąsko     return true;
421cd74dd17STomasz Miąsko   case 'n':
422cd74dd17STomasz Miąsko     Type = BasicType::I128;
423cd74dd17STomasz Miąsko     return true;
424cd74dd17STomasz Miąsko   case 'o':
425cd74dd17STomasz Miąsko     Type = BasicType::U128;
426cd74dd17STomasz Miąsko     return true;
427cd74dd17STomasz Miąsko   case 'p':
428cd74dd17STomasz Miąsko     Type = BasicType::Placeholder;
429cd74dd17STomasz Miąsko     return true;
430cd74dd17STomasz Miąsko   case 's':
431cd74dd17STomasz Miąsko     Type = BasicType::I16;
432cd74dd17STomasz Miąsko     return true;
433cd74dd17STomasz Miąsko   case 't':
434cd74dd17STomasz Miąsko     Type = BasicType::U16;
435cd74dd17STomasz Miąsko     return true;
436cd74dd17STomasz Miąsko   case 'u':
437cd74dd17STomasz Miąsko     Type = BasicType::Unit;
438cd74dd17STomasz Miąsko     return true;
439cd74dd17STomasz Miąsko   case 'v':
440cd74dd17STomasz Miąsko     Type = BasicType::Variadic;
441cd74dd17STomasz Miąsko     return true;
442cd74dd17STomasz Miąsko   case 'x':
443cd74dd17STomasz Miąsko     Type = BasicType::I64;
444cd74dd17STomasz Miąsko     return true;
445cd74dd17STomasz Miąsko   case 'y':
446cd74dd17STomasz Miąsko     Type = BasicType::U64;
447cd74dd17STomasz Miąsko     return true;
448cd74dd17STomasz Miąsko   case 'z':
449cd74dd17STomasz Miąsko     Type = BasicType::Never;
450cd74dd17STomasz Miąsko     return true;
451cd74dd17STomasz Miąsko   default:
452cd74dd17STomasz Miąsko     return false;
453cd74dd17STomasz Miąsko   }
454cd74dd17STomasz Miąsko }
455cd74dd17STomasz Miąsko 
456cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
457cd74dd17STomasz Miąsko   switch (Type) {
458cd74dd17STomasz Miąsko   case BasicType::Bool:
459cd74dd17STomasz Miąsko     print("bool");
460cd74dd17STomasz Miąsko     break;
461cd74dd17STomasz Miąsko   case BasicType::Char:
462cd74dd17STomasz Miąsko     print("char");
463cd74dd17STomasz Miąsko     break;
464cd74dd17STomasz Miąsko   case BasicType::I8:
465cd74dd17STomasz Miąsko     print("i8");
466cd74dd17STomasz Miąsko     break;
467cd74dd17STomasz Miąsko   case BasicType::I16:
468cd74dd17STomasz Miąsko     print("i16");
469cd74dd17STomasz Miąsko     break;
470cd74dd17STomasz Miąsko   case BasicType::I32:
471cd74dd17STomasz Miąsko     print("i32");
472cd74dd17STomasz Miąsko     break;
473cd74dd17STomasz Miąsko   case BasicType::I64:
474cd74dd17STomasz Miąsko     print("i64");
475cd74dd17STomasz Miąsko     break;
476cd74dd17STomasz Miąsko   case BasicType::I128:
477cd74dd17STomasz Miąsko     print("i128");
478cd74dd17STomasz Miąsko     break;
479cd74dd17STomasz Miąsko   case BasicType::ISize:
480cd74dd17STomasz Miąsko     print("isize");
481cd74dd17STomasz Miąsko     break;
482cd74dd17STomasz Miąsko   case BasicType::U8:
483cd74dd17STomasz Miąsko     print("u8");
484cd74dd17STomasz Miąsko     break;
485cd74dd17STomasz Miąsko   case BasicType::U16:
486cd74dd17STomasz Miąsko     print("u16");
487cd74dd17STomasz Miąsko     break;
488cd74dd17STomasz Miąsko   case BasicType::U32:
489cd74dd17STomasz Miąsko     print("u32");
490cd74dd17STomasz Miąsko     break;
491cd74dd17STomasz Miąsko   case BasicType::U64:
492cd74dd17STomasz Miąsko     print("u64");
493cd74dd17STomasz Miąsko     break;
494cd74dd17STomasz Miąsko   case BasicType::U128:
495cd74dd17STomasz Miąsko     print("u128");
496cd74dd17STomasz Miąsko     break;
497cd74dd17STomasz Miąsko   case BasicType::USize:
498cd74dd17STomasz Miąsko     print("usize");
499cd74dd17STomasz Miąsko     break;
500cd74dd17STomasz Miąsko   case BasicType::F32:
501cd74dd17STomasz Miąsko     print("f32");
502cd74dd17STomasz Miąsko     break;
503cd74dd17STomasz Miąsko   case BasicType::F64:
504cd74dd17STomasz Miąsko     print("f64");
505cd74dd17STomasz Miąsko     break;
506cd74dd17STomasz Miąsko   case BasicType::Str:
507cd74dd17STomasz Miąsko     print("str");
508cd74dd17STomasz Miąsko     break;
509cd74dd17STomasz Miąsko   case BasicType::Placeholder:
510cd74dd17STomasz Miąsko     print("_");
511cd74dd17STomasz Miąsko     break;
512cd74dd17STomasz Miąsko   case BasicType::Unit:
513cd74dd17STomasz Miąsko     print("()");
514cd74dd17STomasz Miąsko     break;
515cd74dd17STomasz Miąsko   case BasicType::Variadic:
516cd74dd17STomasz Miąsko     print("...");
517cd74dd17STomasz Miąsko     break;
518cd74dd17STomasz Miąsko   case BasicType::Never:
519cd74dd17STomasz Miąsko     print("!");
520cd74dd17STomasz Miąsko     break;
521cd74dd17STomasz Miąsko   }
5222961f863STomasz Miąsko }
5232961f863STomasz Miąsko 
5242961f863STomasz Miąsko // <type> = | <basic-type>
5252961f863STomasz Miąsko //          | <path>                      // named type
5262961f863STomasz Miąsko //          | "A" <type> <const>          // [T; N]
5272961f863STomasz Miąsko //          | "S" <type>                  // [T]
5282961f863STomasz Miąsko //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
5292961f863STomasz Miąsko //          | "R" [<lifetime>] <type>     // &T
5302961f863STomasz Miąsko //          | "Q" [<lifetime>] <type>     // &mut T
5312961f863STomasz Miąsko //          | "P" <type>                  // *const T
5322961f863STomasz Miąsko //          | "O" <type>                  // *mut T
5332961f863STomasz Miąsko //          | "F" <fn-sig>                // fn(...) -> ...
5342961f863STomasz Miąsko //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
5352961f863STomasz Miąsko //          | <backref>                   // backref
5362961f863STomasz Miąsko void Demangler::demangleType() {
53744d63c57STomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
53844d63c57STomasz Miąsko     Error = true;
53944d63c57STomasz Miąsko     return;
54044d63c57STomasz Miąsko   }
54151f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
54206833297STomasz Miąsko 
54344d63c57STomasz Miąsko   size_t Start = Position;
544b42400ccSTomasz Miąsko   char C = consume();
545b42400ccSTomasz Miąsko   BasicType Type;
546b42400ccSTomasz Miąsko   if (parseBasicType(C, Type))
547b42400ccSTomasz Miąsko     return printBasicType(Type);
548b42400ccSTomasz Miąsko 
549b42400ccSTomasz Miąsko   switch (C) {
550b42400ccSTomasz Miąsko   case 'A':
551b42400ccSTomasz Miąsko     print("[");
552b42400ccSTomasz Miąsko     demangleType();
553b42400ccSTomasz Miąsko     print("; ");
554b42400ccSTomasz Miąsko     demangleConst();
555b42400ccSTomasz Miąsko     print("]");
556b42400ccSTomasz Miąsko     break;
557a84c65c2STomasz Miąsko   case 'S':
558a84c65c2STomasz Miąsko     print("[");
559a84c65c2STomasz Miąsko     demangleType();
560a84c65c2STomasz Miąsko     print("]");
561a84c65c2STomasz Miąsko     break;
562774de7a0STomasz Miąsko   case 'T': {
563774de7a0STomasz Miąsko     print("(");
564774de7a0STomasz Miąsko     size_t I = 0;
565774de7a0STomasz Miąsko     for (; !Error && !consumeIf('E'); ++I) {
566774de7a0STomasz Miąsko       if (I > 0)
567774de7a0STomasz Miąsko         print(", ");
568774de7a0STomasz Miąsko       demangleType();
569774de7a0STomasz Miąsko     }
570774de7a0STomasz Miąsko     if (I == 1)
571774de7a0STomasz Miąsko       print(",");
572774de7a0STomasz Miąsko     print(")");
573774de7a0STomasz Miąsko     break;
574774de7a0STomasz Miąsko   }
575e4fa6c95STomasz Miąsko   case 'R':
576e4fa6c95STomasz Miąsko   case 'Q':
577a67a234eSTomasz Miąsko     print('&');
578a67a234eSTomasz Miąsko     if (consumeIf('L')) {
579a67a234eSTomasz Miąsko       if (auto Lifetime = parseBase62Number()) {
580a67a234eSTomasz Miąsko         printLifetime(Lifetime);
581a67a234eSTomasz Miąsko         print(' ');
582a67a234eSTomasz Miąsko       }
583a67a234eSTomasz Miąsko     }
584a67a234eSTomasz Miąsko     if (C == 'Q')
585a67a234eSTomasz Miąsko       print("mut ");
586e4fa6c95STomasz Miąsko     demangleType();
587e4fa6c95STomasz Miąsko     break;
5886aac5633STomasz Miąsko   case 'P':
5896aac5633STomasz Miąsko     print("*const ");
5906aac5633STomasz Miąsko     demangleType();
5916aac5633STomasz Miąsko     break;
5926aac5633STomasz Miąsko   case 'O':
5936aac5633STomasz Miąsko     print("*mut ");
5946aac5633STomasz Miąsko     demangleType();
5956aac5633STomasz Miąsko     break;
59675cc1cf0STomasz Miąsko   case 'F':
59775cc1cf0STomasz Miąsko     demangleFnSig();
59875cc1cf0STomasz Miąsko     break;
59989615a5eSTomasz Miąsko   case 'D':
60089615a5eSTomasz Miąsko     demangleDynBounds();
60189615a5eSTomasz Miąsko     if (consumeIf('L')) {
60289615a5eSTomasz Miąsko       if (auto Lifetime = parseBase62Number()) {
60389615a5eSTomasz Miąsko         print(" + ");
60489615a5eSTomasz Miąsko         printLifetime(Lifetime);
60589615a5eSTomasz Miąsko       }
60689615a5eSTomasz Miąsko     } else {
60789615a5eSTomasz Miąsko       Error = true;
60889615a5eSTomasz Miąsko     }
60989615a5eSTomasz Miąsko     break;
61044d63c57STomasz Miąsko   case 'B':
61144d63c57STomasz Miąsko     demangleBackref([&] { demangleType(); });
61244d63c57STomasz Miąsko     break;
613b42400ccSTomasz Miąsko   default:
614b42400ccSTomasz Miąsko     Position = Start;
6156cc6ada1STomasz Miąsko     demanglePath(IsInType::Yes);
616b42400ccSTomasz Miąsko     break;
617b42400ccSTomasz Miąsko   }
618cd74dd17STomasz Miąsko }
619cd74dd17STomasz Miąsko 
62075cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
62175cc1cf0STomasz Miąsko // <abi> = "C"
62275cc1cf0STomasz Miąsko //       | <undisambiguated-identifier>
62375cc1cf0STomasz Miąsko void Demangler::demangleFnSig() {
62451f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
625a67a234eSTomasz Miąsko   demangleOptionalBinder();
62675cc1cf0STomasz Miąsko 
62775cc1cf0STomasz Miąsko   if (consumeIf('U'))
62875cc1cf0STomasz Miąsko     print("unsafe ");
62975cc1cf0STomasz Miąsko 
63075cc1cf0STomasz Miąsko   if (consumeIf('K')) {
63175cc1cf0STomasz Miąsko     print("extern \"");
63275cc1cf0STomasz Miąsko     if (consumeIf('C')) {
63375cc1cf0STomasz Miąsko       print("C");
63475cc1cf0STomasz Miąsko     } else {
63575cc1cf0STomasz Miąsko       Identifier Ident = parseIdentifier();
636c8c2b462STomasz Miąsko       if (Ident.Punycode)
637c8c2b462STomasz Miąsko         Error = true;
63875cc1cf0STomasz Miąsko       for (char C : Ident.Name) {
63975cc1cf0STomasz Miąsko         // When mangling ABI string, the "-" is replaced with "_".
64075cc1cf0STomasz Miąsko         if (C == '_')
64175cc1cf0STomasz Miąsko           C = '-';
64275cc1cf0STomasz Miąsko         print(C);
64375cc1cf0STomasz Miąsko       }
64475cc1cf0STomasz Miąsko     }
64575cc1cf0STomasz Miąsko     print("\" ");
64675cc1cf0STomasz Miąsko   }
64775cc1cf0STomasz Miąsko 
64875cc1cf0STomasz Miąsko   print("fn(");
64975cc1cf0STomasz Miąsko   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
65075cc1cf0STomasz Miąsko     if (I > 0)
65175cc1cf0STomasz Miąsko       print(", ");
65275cc1cf0STomasz Miąsko     demangleType();
65375cc1cf0STomasz Miąsko   }
65475cc1cf0STomasz Miąsko   print(")");
65575cc1cf0STomasz Miąsko 
65675cc1cf0STomasz Miąsko   if (consumeIf('u')) {
65775cc1cf0STomasz Miąsko     // Skip the unit type from the output.
65875cc1cf0STomasz Miąsko   } else {
65975cc1cf0STomasz Miąsko     print(" -> ");
66075cc1cf0STomasz Miąsko     demangleType();
66175cc1cf0STomasz Miąsko   }
66275cc1cf0STomasz Miąsko }
66375cc1cf0STomasz Miąsko 
66489615a5eSTomasz Miąsko // <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
66589615a5eSTomasz Miąsko void Demangler::demangleDynBounds() {
66651f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
66789615a5eSTomasz Miąsko   print("dyn ");
66889615a5eSTomasz Miąsko   demangleOptionalBinder();
6691499afa0STomasz Miąsko   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
6701499afa0STomasz Miąsko     if (I > 0)
6711499afa0STomasz Miąsko       print(" + ");
6721499afa0STomasz Miąsko     demangleDynTrait();
6731499afa0STomasz Miąsko   }
6741499afa0STomasz Miąsko }
6751499afa0STomasz Miąsko 
6761499afa0STomasz Miąsko // <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
6771499afa0STomasz Miąsko // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
6781499afa0STomasz Miąsko void Demangler::demangleDynTrait() {
6796cc6ada1STomasz Miąsko   bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes);
680619a65e5STomasz Miąsko   while (!Error && consumeIf('p')) {
681619a65e5STomasz Miąsko     if (!IsOpen) {
682619a65e5STomasz Miąsko       IsOpen = true;
683619a65e5STomasz Miąsko       print('<');
684619a65e5STomasz Miąsko     } else {
685619a65e5STomasz Miąsko       print(", ");
686619a65e5STomasz Miąsko     }
687619a65e5STomasz Miąsko     print(parseIdentifier().Name);
688619a65e5STomasz Miąsko     print(" = ");
689619a65e5STomasz Miąsko     demangleType();
690619a65e5STomasz Miąsko   }
691619a65e5STomasz Miąsko   if (IsOpen)
692619a65e5STomasz Miąsko     print(">");
69389615a5eSTomasz Miąsko }
69489615a5eSTomasz Miąsko 
695a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes.
696a67a234eSTomasz Miąsko //
697a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number>
698a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() {
699a67a234eSTomasz Miąsko   uint64_t Binder = parseOptionalBase62Number('G');
700a67a234eSTomasz Miąsko   if (Error || Binder == 0)
701a67a234eSTomasz Miąsko     return;
702a67a234eSTomasz Miąsko 
703a67a234eSTomasz Miąsko   // In valid inputs each bound lifetime is referenced later. Referencing a
704a67a234eSTomasz Miąsko   // lifetime requires at least one byte of input. Reject inputs that are too
705a67a234eSTomasz Miąsko   // short to reference all bound lifetimes. Otherwise demangling of invalid
706a67a234eSTomasz Miąsko   // binders could generate excessive amounts of output.
707a67a234eSTomasz Miąsko   if (Binder >= Input.size() - BoundLifetimes) {
708a67a234eSTomasz Miąsko     Error = true;
709a67a234eSTomasz Miąsko     return;
710a67a234eSTomasz Miąsko   }
711a67a234eSTomasz Miąsko 
712a67a234eSTomasz Miąsko   print("for<");
713a67a234eSTomasz Miąsko   for (size_t I = 0; I != Binder; ++I) {
714a67a234eSTomasz Miąsko     BoundLifetimes += 1;
715a67a234eSTomasz Miąsko     if (I > 0)
716a67a234eSTomasz Miąsko       print(", ");
717a67a234eSTomasz Miąsko     printLifetime(1);
718a67a234eSTomasz Miąsko   }
719a67a234eSTomasz Miąsko   print("> ");
720a67a234eSTomasz Miąsko }
721a67a234eSTomasz Miąsko 
722cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
723cd74dd17STomasz Miąsko //         | "p"                          // placeholder
724cd74dd17STomasz Miąsko //         | <backref>
725cd74dd17STomasz Miąsko void Demangler::demangleConst() {
726f9a79356STomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
727f9a79356STomasz Miąsko     Error = true;
728f9a79356STomasz Miąsko     return;
729f9a79356STomasz Miąsko   }
73051f6caf2SNathan Sidwell   ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
731f9a79356STomasz Miąsko 
732f9a79356STomasz Miąsko   char C = consume();
733cd74dd17STomasz Miąsko   BasicType Type;
734f9a79356STomasz Miąsko   if (parseBasicType(C, Type)) {
735cd74dd17STomasz Miąsko     switch (Type) {
736cd74dd17STomasz Miąsko     case BasicType::I8:
737cd74dd17STomasz Miąsko     case BasicType::I16:
738cd74dd17STomasz Miąsko     case BasicType::I32:
739cd74dd17STomasz Miąsko     case BasicType::I64:
740cd74dd17STomasz Miąsko     case BasicType::I128:
741cd74dd17STomasz Miąsko     case BasicType::ISize:
742cd74dd17STomasz Miąsko     case BasicType::U8:
743cd74dd17STomasz Miąsko     case BasicType::U16:
744cd74dd17STomasz Miąsko     case BasicType::U32:
745cd74dd17STomasz Miąsko     case BasicType::U64:
746cd74dd17STomasz Miąsko     case BasicType::U128:
747cd74dd17STomasz Miąsko     case BasicType::USize:
748cd74dd17STomasz Miąsko       demangleConstInt();
749cd74dd17STomasz Miąsko       break;
750fc0f2bb9STomasz Miąsko     case BasicType::Bool:
751fc0f2bb9STomasz Miąsko       demangleConstBool();
752fc0f2bb9STomasz Miąsko       break;
7532ba49f6aSTomasz Miąsko     case BasicType::Char:
7542ba49f6aSTomasz Miąsko       demangleConstChar();
7552ba49f6aSTomasz Miąsko       break;
756cd74dd17STomasz Miąsko     case BasicType::Placeholder:
757cd74dd17STomasz Miąsko       print('_');
758cd74dd17STomasz Miąsko       break;
759cd74dd17STomasz Miąsko     default:
7602961f863STomasz Miąsko       Error = true;
761cd74dd17STomasz Miąsko       break;
762cd74dd17STomasz Miąsko     }
763f9a79356STomasz Miąsko   } else if (C == 'B') {
764f9a79356STomasz Miąsko     demangleBackref([&] { demangleConst(); });
765cd74dd17STomasz Miąsko   } else {
766cd74dd17STomasz Miąsko     Error = true;
767cd74dd17STomasz Miąsko   }
768cd74dd17STomasz Miąsko }
769cd74dd17STomasz Miąsko 
770cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
771cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
772cd74dd17STomasz Miąsko   if (consumeIf('n'))
773cd74dd17STomasz Miąsko     print('-');
774cd74dd17STomasz Miąsko 
7757c59e800SNick Desaulniers   std::string_view HexDigits;
776cd74dd17STomasz Miąsko   uint64_t Value = parseHexNumber(HexDigits);
777cd74dd17STomasz Miąsko   if (HexDigits.size() <= 16) {
778cd74dd17STomasz Miąsko     printDecimalNumber(Value);
779cd74dd17STomasz Miąsko   } else {
780cd74dd17STomasz Miąsko     print("0x");
781cd74dd17STomasz Miąsko     print(HexDigits);
7822961f863STomasz Miąsko   }
7832961f863STomasz Miąsko }
7842961f863STomasz Miąsko 
785fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
786fc0f2bb9STomasz Miąsko //              | "1_" // true
787fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
7887c59e800SNick Desaulniers   std::string_view HexDigits;
789fc0f2bb9STomasz Miąsko   parseHexNumber(HexDigits);
790fc0f2bb9STomasz Miąsko   if (HexDigits == "0")
791fc0f2bb9STomasz Miąsko     print("false");
792fc0f2bb9STomasz Miąsko   else if (HexDigits == "1")
793fc0f2bb9STomasz Miąsko     print("true");
794fc0f2bb9STomasz Miąsko   else
795fc0f2bb9STomasz Miąsko     Error = true;
796fc0f2bb9STomasz Miąsko }
797fc0f2bb9STomasz Miąsko 
7982ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character.
7992ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) {
8002ba49f6aSTomasz Miąsko   return 0x20 <= CodePoint && CodePoint <= 0x7e;
8012ba49f6aSTomasz Miąsko }
8022ba49f6aSTomasz Miąsko 
8032ba49f6aSTomasz Miąsko // <const-data> = <hex-number>
8042ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() {
8057c59e800SNick Desaulniers   std::string_view HexDigits;
8062ba49f6aSTomasz Miąsko   uint64_t CodePoint = parseHexNumber(HexDigits);
8072ba49f6aSTomasz Miąsko   if (Error || HexDigits.size() > 6) {
8082ba49f6aSTomasz Miąsko     Error = true;
8092ba49f6aSTomasz Miąsko     return;
8102ba49f6aSTomasz Miąsko   }
8112ba49f6aSTomasz Miąsko 
8122ba49f6aSTomasz Miąsko   print("'");
8132ba49f6aSTomasz Miąsko   switch (CodePoint) {
8142ba49f6aSTomasz Miąsko   case '\t':
8152ba49f6aSTomasz Miąsko     print(R"(\t)");
8162ba49f6aSTomasz Miąsko     break;
8172ba49f6aSTomasz Miąsko   case '\r':
8182ba49f6aSTomasz Miąsko     print(R"(\r)");
8192ba49f6aSTomasz Miąsko     break;
8202ba49f6aSTomasz Miąsko   case '\n':
8212ba49f6aSTomasz Miąsko     print(R"(\n)");
8222ba49f6aSTomasz Miąsko     break;
8232ba49f6aSTomasz Miąsko   case '\\':
8242ba49f6aSTomasz Miąsko     print(R"(\\)");
8252ba49f6aSTomasz Miąsko     break;
8262ba49f6aSTomasz Miąsko   case '"':
8272ba49f6aSTomasz Miąsko     print(R"(")");
8282ba49f6aSTomasz Miąsko     break;
8292ba49f6aSTomasz Miąsko   case '\'':
8302ba49f6aSTomasz Miąsko     print(R"(\')");
8312ba49f6aSTomasz Miąsko     break;
8322ba49f6aSTomasz Miąsko   default:
8332ba49f6aSTomasz Miąsko     if (isAsciiPrintable(CodePoint)) {
8342ba49f6aSTomasz Miąsko       char C = CodePoint;
8352ba49f6aSTomasz Miąsko       print(C);
8362ba49f6aSTomasz Miąsko     } else {
8372ba49f6aSTomasz Miąsko       print(R"(\u{)");
8382ba49f6aSTomasz Miąsko       print(HexDigits);
8392ba49f6aSTomasz Miąsko       print('}');
8402ba49f6aSTomasz Miąsko     }
8412ba49f6aSTomasz Miąsko     break;
8422ba49f6aSTomasz Miąsko   }
8432ba49f6aSTomasz Miąsko   print('\'');
8442ba49f6aSTomasz Miąsko }
8452ba49f6aSTomasz Miąsko 
8467310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
8477310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
8487310403eSTomasz Miąsko   bool Punycode = consumeIf('u');
8497310403eSTomasz Miąsko   uint64_t Bytes = parseDecimalNumber();
8507310403eSTomasz Miąsko 
8517310403eSTomasz Miąsko   // Underscore resolves the ambiguity when identifier starts with a decimal
8527310403eSTomasz Miąsko   // digit or another underscore.
8537310403eSTomasz Miąsko   consumeIf('_');
8547310403eSTomasz Miąsko 
8557310403eSTomasz Miąsko   if (Error || Bytes > Input.size() - Position) {
8567310403eSTomasz Miąsko     Error = true;
8577310403eSTomasz Miąsko     return {};
8587310403eSTomasz Miąsko   }
8597c59e800SNick Desaulniers   std::string_view S = Input.substr(Position, Bytes);
8607310403eSTomasz Miąsko   Position += Bytes;
8617310403eSTomasz Miąsko 
86298277923SBenjamin Kramer   if (!std::all_of(S.begin(), S.end(), isValid)) {
8637310403eSTomasz Miąsko     Error = true;
8647310403eSTomasz Miąsko     return {};
8657310403eSTomasz Miąsko   }
8667310403eSTomasz Miąsko 
8677310403eSTomasz Miąsko   return {S, Punycode};
8687310403eSTomasz Miąsko }
8697310403eSTomasz Miąsko 
8707310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
871a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
872a67a234eSTomasz Miąsko //
873*9ae24fcaSNico Weber // This function is intended for parsing disambiguators and binders which when
874a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded
875a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
876a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0.
87778e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
87878e94915STomasz Miąsko   if (!consumeIf(Tag))
87978e94915STomasz Miąsko     return 0;
88078e94915STomasz Miąsko 
88178e94915STomasz Miąsko   uint64_t N = parseBase62Number();
88278e94915STomasz Miąsko   if (Error || !addAssign(N, 1))
88378e94915STomasz Miąsko     return 0;
88478e94915STomasz Miąsko 
88578e94915STomasz Miąsko   return N;
8867310403eSTomasz Miąsko }
8877310403eSTomasz Miąsko 
8887310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
8897310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
8907310403eSTomasz Miąsko // "1_" encodes 2, etc.
8917310403eSTomasz Miąsko //
8927310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
8937310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
8947310403eSTomasz Miąsko   if (consumeIf('_'))
8957310403eSTomasz Miąsko     return 0;
8967310403eSTomasz Miąsko 
8977310403eSTomasz Miąsko   uint64_t Value = 0;
8987310403eSTomasz Miąsko 
8997310403eSTomasz Miąsko   while (true) {
9007310403eSTomasz Miąsko     uint64_t Digit;
9017310403eSTomasz Miąsko     char C = consume();
9027310403eSTomasz Miąsko 
9037310403eSTomasz Miąsko     if (C == '_') {
9047310403eSTomasz Miąsko       break;
9057310403eSTomasz Miąsko     } else if (isDigit(C)) {
9067310403eSTomasz Miąsko       Digit = C - '0';
9077310403eSTomasz Miąsko     } else if (isLower(C)) {
9087310403eSTomasz Miąsko       Digit = 10 + (C - 'a');
9097310403eSTomasz Miąsko     } else if (isUpper(C)) {
9107310403eSTomasz Miąsko       Digit = 10 + 26 + (C - 'A');
9117310403eSTomasz Miąsko     } else {
9127310403eSTomasz Miąsko       Error = true;
9137310403eSTomasz Miąsko       return 0;
9147310403eSTomasz Miąsko     }
9157310403eSTomasz Miąsko 
9167310403eSTomasz Miąsko     if (!mulAssign(Value, 62))
9177310403eSTomasz Miąsko       return 0;
9187310403eSTomasz Miąsko 
9197310403eSTomasz Miąsko     if (!addAssign(Value, Digit))
9207310403eSTomasz Miąsko       return 0;
9217310403eSTomasz Miąsko   }
9227310403eSTomasz Miąsko 
9237310403eSTomasz Miąsko   if (!addAssign(Value, 1))
9247310403eSTomasz Miąsko     return 0;
9257310403eSTomasz Miąsko 
9267310403eSTomasz Miąsko   return Value;
9277310403eSTomasz Miąsko }
9287310403eSTomasz Miąsko 
9297310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
9307310403eSTomasz Miąsko //
9317310403eSTomasz Miąsko // <decimal-number> = "0"
9327310403eSTomasz Miąsko //                  | <1-9> {<0-9>}
9337310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
9347310403eSTomasz Miąsko   char C = look();
9357310403eSTomasz Miąsko   if (!isDigit(C)) {
9367310403eSTomasz Miąsko     Error = true;
9377310403eSTomasz Miąsko     return 0;
9387310403eSTomasz Miąsko   }
9397310403eSTomasz Miąsko 
9407310403eSTomasz Miąsko   if (C == '0') {
9417310403eSTomasz Miąsko     consume();
9427310403eSTomasz Miąsko     return 0;
9437310403eSTomasz Miąsko   }
9447310403eSTomasz Miąsko 
9457310403eSTomasz Miąsko   uint64_t Value = 0;
9467310403eSTomasz Miąsko 
9477310403eSTomasz Miąsko   while (isDigit(look())) {
9487310403eSTomasz Miąsko     if (!mulAssign(Value, 10)) {
9497310403eSTomasz Miąsko       Error = true;
9507310403eSTomasz Miąsko       return 0;
9517310403eSTomasz Miąsko     }
9527310403eSTomasz Miąsko 
9537310403eSTomasz Miąsko     uint64_t D = consume() - '0';
9547310403eSTomasz Miąsko     if (!addAssign(Value, D))
9557310403eSTomasz Miąsko       return 0;
9567310403eSTomasz Miąsko   }
9577310403eSTomasz Miąsko 
9587310403eSTomasz Miąsko   return Value;
9597310403eSTomasz Miąsko }
960cd74dd17STomasz Miąsko 
961cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
962cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
963cd74dd17STomasz Miąsko // HexDigits.size() > 16.
964cd74dd17STomasz Miąsko //
965cd74dd17STomasz Miąsko // <hex-number> = "0_"
966cd74dd17STomasz Miąsko //              | <1-9a-f> {<0-9a-f>} "_"
9677c59e800SNick Desaulniers uint64_t Demangler::parseHexNumber(std::string_view &HexDigits) {
968cd74dd17STomasz Miąsko   size_t Start = Position;
969cd74dd17STomasz Miąsko   uint64_t Value = 0;
970cd74dd17STomasz Miąsko 
971cd74dd17STomasz Miąsko   if (!isHexDigit(look()))
972cd74dd17STomasz Miąsko     Error = true;
973cd74dd17STomasz Miąsko 
974cd74dd17STomasz Miąsko   if (consumeIf('0')) {
975cd74dd17STomasz Miąsko     if (!consumeIf('_'))
976cd74dd17STomasz Miąsko       Error = true;
977cd74dd17STomasz Miąsko   } else {
978cd74dd17STomasz Miąsko     while (!Error && !consumeIf('_')) {
979cd74dd17STomasz Miąsko       char C = consume();
980cd74dd17STomasz Miąsko       Value *= 16;
981cd74dd17STomasz Miąsko       if (isDigit(C))
982cd74dd17STomasz Miąsko         Value += C - '0';
983cd74dd17STomasz Miąsko       else if ('a' <= C && C <= 'f')
984cd74dd17STomasz Miąsko         Value += 10 + (C - 'a');
985cd74dd17STomasz Miąsko       else
986cd74dd17STomasz Miąsko         Error = true;
987cd74dd17STomasz Miąsko     }
988cd74dd17STomasz Miąsko   }
989cd74dd17STomasz Miąsko 
990cd74dd17STomasz Miąsko   if (Error) {
9917c59e800SNick Desaulniers     HexDigits = std::string_view();
992cd74dd17STomasz Miąsko     return 0;
993cd74dd17STomasz Miąsko   }
994cd74dd17STomasz Miąsko 
995cd74dd17STomasz Miąsko   size_t End = Position - 1;
996cd74dd17STomasz Miąsko   assert(Start < End);
997cd74dd17STomasz Miąsko   HexDigits = Input.substr(Start, End - Start);
998cd74dd17STomasz Miąsko   return Value;
999cd74dd17STomasz Miąsko }
1000a67a234eSTomasz Miąsko 
10016cc6ada1STomasz Miąsko void Demangler::print(char C) {
10026cc6ada1STomasz Miąsko   if (Error || !Print)
10036cc6ada1STomasz Miąsko     return;
10046cc6ada1STomasz Miąsko 
10056cc6ada1STomasz Miąsko   Output += C;
10066cc6ada1STomasz Miąsko }
10076cc6ada1STomasz Miąsko 
10087c59e800SNick Desaulniers void Demangler::print(std::string_view S) {
10096cc6ada1STomasz Miąsko   if (Error || !Print)
10106cc6ada1STomasz Miąsko     return;
10116cc6ada1STomasz Miąsko 
10126cc6ada1STomasz Miąsko   Output += S;
10136cc6ada1STomasz Miąsko }
10146cc6ada1STomasz Miąsko 
10156cc6ada1STomasz Miąsko void Demangler::printDecimalNumber(uint64_t N) {
10166cc6ada1STomasz Miąsko   if (Error || !Print)
10176cc6ada1STomasz Miąsko     return;
10186cc6ada1STomasz Miąsko 
10196cc6ada1STomasz Miąsko   Output << N;
10206cc6ada1STomasz Miąsko }
10216cc6ada1STomasz Miąsko 
1022a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
1023a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
1024a67a234eSTomasz Miąsko // bound by one of the enclosing binders.
1025a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) {
1026a67a234eSTomasz Miąsko   if (Index == 0) {
1027a67a234eSTomasz Miąsko     print("'_");
1028a67a234eSTomasz Miąsko     return;
1029a67a234eSTomasz Miąsko   }
1030a67a234eSTomasz Miąsko 
1031a67a234eSTomasz Miąsko   if (Index - 1 >= BoundLifetimes) {
1032a67a234eSTomasz Miąsko     Error = true;
1033a67a234eSTomasz Miąsko     return;
1034a67a234eSTomasz Miąsko   }
1035a67a234eSTomasz Miąsko 
1036a67a234eSTomasz Miąsko   uint64_t Depth = BoundLifetimes - Index;
1037a67a234eSTomasz Miąsko   print('\'');
1038a67a234eSTomasz Miąsko   if (Depth < 26) {
1039a67a234eSTomasz Miąsko     char C = 'a' + Depth;
1040a67a234eSTomasz Miąsko     print(C);
1041a67a234eSTomasz Miąsko   } else {
1042a67a234eSTomasz Miąsko     print('z');
1043a67a234eSTomasz Miąsko     printDecimalNumber(Depth - 26 + 1);
1044a67a234eSTomasz Miąsko   }
1045a67a234eSTomasz Miąsko }
10466cc6ada1STomasz Miąsko 
1047c8c2b462STomasz Miąsko static inline bool decodePunycodeDigit(char C, size_t &Value) {
1048c8c2b462STomasz Miąsko   if (isLower(C)) {
1049c8c2b462STomasz Miąsko     Value = C - 'a';
1050c8c2b462STomasz Miąsko     return true;
1051c8c2b462STomasz Miąsko   }
1052c8c2b462STomasz Miąsko 
1053c8c2b462STomasz Miąsko   if (isDigit(C)) {
1054c8c2b462STomasz Miąsko     Value = 26 + (C - '0');
1055c8c2b462STomasz Miąsko     return true;
1056c8c2b462STomasz Miąsko   }
1057c8c2b462STomasz Miąsko 
1058c8c2b462STomasz Miąsko   return false;
1059c8c2b462STomasz Miąsko }
1060c8c2b462STomasz Miąsko 
10612e97236aSLuís Ferreira static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) {
1062c8c2b462STomasz Miąsko   char *Buffer = Output.getBuffer();
1063c8c2b462STomasz Miąsko   char *Start = Buffer + StartIdx;
1064c8c2b462STomasz Miąsko   char *End = Buffer + Output.getCurrentPosition();
1065c8c2b462STomasz Miąsko   Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer);
1066c8c2b462STomasz Miąsko }
1067c8c2b462STomasz Miąsko 
1068c8c2b462STomasz Miąsko // Encodes code point as UTF-8 and stores results in Output. Returns false if
1069c8c2b462STomasz Miąsko // CodePoint is not a valid unicode scalar value.
1070c8c2b462STomasz Miąsko static inline bool encodeUTF8(size_t CodePoint, char *Output) {
1071c8c2b462STomasz Miąsko   if (0xD800 <= CodePoint && CodePoint <= 0xDFFF)
1072c8c2b462STomasz Miąsko     return false;
1073c8c2b462STomasz Miąsko 
1074c8c2b462STomasz Miąsko   if (CodePoint <= 0x7F) {
1075c8c2b462STomasz Miąsko     Output[0] = CodePoint;
1076c8c2b462STomasz Miąsko     return true;
1077c8c2b462STomasz Miąsko   }
1078c8c2b462STomasz Miąsko 
1079c8c2b462STomasz Miąsko   if (CodePoint <= 0x7FF) {
1080c8c2b462STomasz Miąsko     Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F);
1081c8c2b462STomasz Miąsko     Output[1] = 0x80 | (CodePoint & 0x3F);
1082c8c2b462STomasz Miąsko     return true;
1083c8c2b462STomasz Miąsko   }
1084c8c2b462STomasz Miąsko 
1085c8c2b462STomasz Miąsko   if (CodePoint <= 0xFFFF) {
1086c8c2b462STomasz Miąsko     Output[0] = 0xE0 | (CodePoint >> 12);
1087c8c2b462STomasz Miąsko     Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F);
1088c8c2b462STomasz Miąsko     Output[2] = 0x80 | (CodePoint & 0x3F);
1089c8c2b462STomasz Miąsko     return true;
1090c8c2b462STomasz Miąsko   }
1091c8c2b462STomasz Miąsko 
1092c8c2b462STomasz Miąsko   if (CodePoint <= 0x10FFFF) {
1093c8c2b462STomasz Miąsko     Output[0] = 0xF0 | (CodePoint >> 18);
1094c8c2b462STomasz Miąsko     Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F);
1095c8c2b462STomasz Miąsko     Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F);
1096c8c2b462STomasz Miąsko     Output[3] = 0x80 | (CodePoint & 0x3F);
1097c8c2b462STomasz Miąsko     return true;
1098c8c2b462STomasz Miąsko   }
1099c8c2b462STomasz Miąsko 
1100c8c2b462STomasz Miąsko   return false;
1101c8c2b462STomasz Miąsko }
1102c8c2b462STomasz Miąsko 
1103c8c2b462STomasz Miąsko // Decodes string encoded using punycode and appends results to Output.
1104c8c2b462STomasz Miąsko // Returns true if decoding was successful.
11057c59e800SNick Desaulniers static bool decodePunycode(std::string_view Input, OutputBuffer &Output) {
1106c8c2b462STomasz Miąsko   size_t OutputSize = Output.getCurrentPosition();
1107c8c2b462STomasz Miąsko   size_t InputIdx = 0;
1108c8c2b462STomasz Miąsko 
1109c8c2b462STomasz Miąsko   // Rust uses an underscore as a delimiter.
11107c59e800SNick Desaulniers   size_t DelimiterPos = std::string_view::npos;
1111c8c2b462STomasz Miąsko   for (size_t I = 0; I != Input.size(); ++I)
1112c8c2b462STomasz Miąsko     if (Input[I] == '_')
1113c8c2b462STomasz Miąsko       DelimiterPos = I;
1114c8c2b462STomasz Miąsko 
11157c59e800SNick Desaulniers   if (DelimiterPos != std::string_view::npos) {
1116c8c2b462STomasz Miąsko     // Copy basic code points before the last delimiter to the output.
1117c8c2b462STomasz Miąsko     for (; InputIdx != DelimiterPos; ++InputIdx) {
1118c8c2b462STomasz Miąsko       char C = Input[InputIdx];
1119c8c2b462STomasz Miąsko       if (!isValid(C))
1120c8c2b462STomasz Miąsko         return false;
1121c8c2b462STomasz Miąsko       // Code points are padded with zeros while decoding is in progress.
1122c8c2b462STomasz Miąsko       char UTF8[4] = {C};
11237c59e800SNick Desaulniers       Output += std::string_view(UTF8, 4);
1124c8c2b462STomasz Miąsko     }
1125c8c2b462STomasz Miąsko     // Skip over the delimiter.
1126c8c2b462STomasz Miąsko     ++InputIdx;
1127c8c2b462STomasz Miąsko   }
1128c8c2b462STomasz Miąsko 
1129c8c2b462STomasz Miąsko   size_t Base = 36;
1130c8c2b462STomasz Miąsko   size_t Skew = 38;
1131c8c2b462STomasz Miąsko   size_t Bias = 72;
1132c8c2b462STomasz Miąsko   size_t N = 0x80;
1133c8c2b462STomasz Miąsko   size_t TMin = 1;
1134c8c2b462STomasz Miąsko   size_t TMax = 26;
1135c8c2b462STomasz Miąsko   size_t Damp = 700;
1136c8c2b462STomasz Miąsko 
1137c8c2b462STomasz Miąsko   auto Adapt = [&](size_t Delta, size_t NumPoints) {
1138c8c2b462STomasz Miąsko     Delta /= Damp;
1139c8c2b462STomasz Miąsko     Delta += Delta / NumPoints;
1140c8c2b462STomasz Miąsko     Damp = 2;
1141c8c2b462STomasz Miąsko 
1142c8c2b462STomasz Miąsko     size_t K = 0;
1143c8c2b462STomasz Miąsko     while (Delta > (Base - TMin) * TMax / 2) {
1144c8c2b462STomasz Miąsko       Delta /= Base - TMin;
1145c8c2b462STomasz Miąsko       K += Base;
1146c8c2b462STomasz Miąsko     }
1147c8c2b462STomasz Miąsko     return K + (((Base - TMin + 1) * Delta) / (Delta + Skew));
1148c8c2b462STomasz Miąsko   };
1149c8c2b462STomasz Miąsko 
1150c8c2b462STomasz Miąsko   // Main decoding loop.
1151c8c2b462STomasz Miąsko   for (size_t I = 0; InputIdx != Input.size(); I += 1) {
1152c8c2b462STomasz Miąsko     size_t OldI = I;
1153c8c2b462STomasz Miąsko     size_t W = 1;
1154c8c2b462STomasz Miąsko     size_t Max = std::numeric_limits<size_t>::max();
1155c8c2b462STomasz Miąsko     for (size_t K = Base; true; K += Base) {
1156c8c2b462STomasz Miąsko       if (InputIdx == Input.size())
1157c8c2b462STomasz Miąsko         return false;
1158c8c2b462STomasz Miąsko       char C = Input[InputIdx++];
1159c8c2b462STomasz Miąsko       size_t Digit = 0;
1160c8c2b462STomasz Miąsko       if (!decodePunycodeDigit(C, Digit))
1161c8c2b462STomasz Miąsko         return false;
1162c8c2b462STomasz Miąsko 
1163c8c2b462STomasz Miąsko       if (Digit > (Max - I) / W)
1164c8c2b462STomasz Miąsko         return false;
1165c8c2b462STomasz Miąsko       I += Digit * W;
1166c8c2b462STomasz Miąsko 
1167c8c2b462STomasz Miąsko       size_t T;
1168c8c2b462STomasz Miąsko       if (K <= Bias)
1169c8c2b462STomasz Miąsko         T = TMin;
1170c8c2b462STomasz Miąsko       else if (K >= Bias + TMax)
1171c8c2b462STomasz Miąsko         T = TMax;
1172c8c2b462STomasz Miąsko       else
1173c8c2b462STomasz Miąsko         T = K - Bias;
1174c8c2b462STomasz Miąsko 
1175c8c2b462STomasz Miąsko       if (Digit < T)
1176c8c2b462STomasz Miąsko         break;
1177c8c2b462STomasz Miąsko 
1178c8c2b462STomasz Miąsko       if (W > Max / (Base - T))
1179c8c2b462STomasz Miąsko         return false;
1180c8c2b462STomasz Miąsko       W *= (Base - T);
1181c8c2b462STomasz Miąsko     }
1182c8c2b462STomasz Miąsko     size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1;
1183c8c2b462STomasz Miąsko     Bias = Adapt(I - OldI, NumPoints);
1184c8c2b462STomasz Miąsko 
1185c8c2b462STomasz Miąsko     if (I / NumPoints > Max - N)
1186c8c2b462STomasz Miąsko       return false;
1187c8c2b462STomasz Miąsko     N += I / NumPoints;
1188c8c2b462STomasz Miąsko     I = I % NumPoints;
1189c8c2b462STomasz Miąsko 
1190c8c2b462STomasz Miąsko     // Insert N at position I in the output.
1191c8c2b462STomasz Miąsko     char UTF8[4] = {};
1192c8c2b462STomasz Miąsko     if (!encodeUTF8(N, UTF8))
1193c8c2b462STomasz Miąsko       return false;
1194c8c2b462STomasz Miąsko     Output.insert(OutputSize + I * 4, UTF8, 4);
1195c8c2b462STomasz Miąsko   }
1196c8c2b462STomasz Miąsko 
1197c8c2b462STomasz Miąsko   removeNullBytes(Output, OutputSize);
1198c8c2b462STomasz Miąsko   return true;
1199c8c2b462STomasz Miąsko }
1200c8c2b462STomasz Miąsko 
1201c8c2b462STomasz Miąsko void Demangler::printIdentifier(Identifier Ident) {
1202c8c2b462STomasz Miąsko   if (Error || !Print)
1203c8c2b462STomasz Miąsko     return;
1204c8c2b462STomasz Miąsko 
1205c8c2b462STomasz Miąsko   if (Ident.Punycode) {
1206c8c2b462STomasz Miąsko     if (!decodePunycode(Ident.Name, Output))
1207c8c2b462STomasz Miąsko       Error = true;
1208c8c2b462STomasz Miąsko   } else {
1209c8c2b462STomasz Miąsko     print(Ident.Name);
1210c8c2b462STomasz Miąsko   }
1211c8c2b462STomasz Miąsko }
1212c8c2b462STomasz Miąsko 
12136cc6ada1STomasz Miąsko char Demangler::look() const {
12146cc6ada1STomasz Miąsko   if (Error || Position >= Input.size())
12156cc6ada1STomasz Miąsko     return 0;
12166cc6ada1STomasz Miąsko 
12176cc6ada1STomasz Miąsko   return Input[Position];
12186cc6ada1STomasz Miąsko }
12196cc6ada1STomasz Miąsko 
12206cc6ada1STomasz Miąsko char Demangler::consume() {
12216cc6ada1STomasz Miąsko   if (Error || Position >= Input.size()) {
12226cc6ada1STomasz Miąsko     Error = true;
12236cc6ada1STomasz Miąsko     return 0;
12246cc6ada1STomasz Miąsko   }
12256cc6ada1STomasz Miąsko 
12266cc6ada1STomasz Miąsko   return Input[Position++];
12276cc6ada1STomasz Miąsko }
12286cc6ada1STomasz Miąsko 
12296cc6ada1STomasz Miąsko bool Demangler::consumeIf(char Prefix) {
12306cc6ada1STomasz Miąsko   if (Error || Position >= Input.size() || Input[Position] != Prefix)
12316cc6ada1STomasz Miąsko     return false;
12326cc6ada1STomasz Miąsko 
12336cc6ada1STomasz Miąsko   Position += 1;
12346cc6ada1STomasz Miąsko   return true;
12356cc6ada1STomasz Miąsko }
12366cc6ada1STomasz Miąsko 
12376cc6ada1STomasz Miąsko /// Computes A + B. When computation wraps around sets the error and returns
12386cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
12396cc6ada1STomasz Miąsko bool Demangler::addAssign(uint64_t &A, uint64_t B) {
12406cc6ada1STomasz Miąsko   if (A > std::numeric_limits<uint64_t>::max() - B) {
12416cc6ada1STomasz Miąsko     Error = true;
12426cc6ada1STomasz Miąsko     return false;
12436cc6ada1STomasz Miąsko   }
12446cc6ada1STomasz Miąsko 
12456cc6ada1STomasz Miąsko   A += B;
12466cc6ada1STomasz Miąsko   return true;
12476cc6ada1STomasz Miąsko }
12486cc6ada1STomasz Miąsko 
12496cc6ada1STomasz Miąsko /// Computes A * B. When computation wraps around sets the error and returns
12506cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
12516cc6ada1STomasz Miąsko bool Demangler::mulAssign(uint64_t &A, uint64_t B) {
12526cc6ada1STomasz Miąsko   if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) {
12536cc6ada1STomasz Miąsko     Error = true;
12546cc6ada1STomasz Miąsko     return false;
12556cc6ada1STomasz Miąsko   }
12566cc6ada1STomasz Miąsko 
12576cc6ada1STomasz Miąsko   A *= B;
12586cc6ada1STomasz Miąsko   return true;
12596cc6ada1STomasz Miąsko }
1260