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