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;
106*a67a234eSTomasz 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   }
1127310403eSTomasz Miąsko   Input = Mangled;
1137310403eSTomasz Miąsko 
11457f40886STomasz Miąsko   demanglePath(rust_demangle::InType::No);
1157310403eSTomasz Miąsko 
1167310403eSTomasz Miąsko   // FIXME parse optional <instantiating-crate>.
1177310403eSTomasz Miąsko 
1187310403eSTomasz Miąsko   if (Position != Input.size())
1197310403eSTomasz Miąsko     Error = true;
1207310403eSTomasz Miąsko 
1217310403eSTomasz Miąsko   return !Error;
1227310403eSTomasz Miąsko }
1237310403eSTomasz Miąsko 
12406833297STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type.
12506833297STomasz Miąsko //
1267310403eSTomasz Miąsko // <path> = "C" <identifier>               // crate root
1277310403eSTomasz Miąsko //        | "M" <impl-path> <type>         // <T> (inherent impl)
1287310403eSTomasz Miąsko //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
1297310403eSTomasz Miąsko //        | "Y" <type> <path>              // <T as Trait> (trait definition)
1307310403eSTomasz Miąsko //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
1317310403eSTomasz Miąsko //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
1327310403eSTomasz Miąsko //        | <backref>
1337310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
1347310403eSTomasz Miąsko // <ns> = "C"      // closure
1357310403eSTomasz Miąsko //      | "S"      // shim
1367310403eSTomasz Miąsko //      | <A-Z>    // other special namespaces
1377310403eSTomasz Miąsko //      | <a-z>    // internal namespaces
13806833297STomasz Miąsko void Demangler::demanglePath(InType InType) {
1397310403eSTomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
1407310403eSTomasz Miąsko     Error = true;
1417310403eSTomasz Miąsko     return;
1427310403eSTomasz Miąsko   }
14378e94915STomasz Miąsko   SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
1447310403eSTomasz Miąsko 
1457310403eSTomasz Miąsko   switch (consume()) {
1467310403eSTomasz Miąsko   case 'C': {
1477310403eSTomasz Miąsko     parseOptionalBase62Number('s');
1487310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1497310403eSTomasz Miąsko     print(Ident.Name);
1507310403eSTomasz Miąsko     break;
1517310403eSTomasz Miąsko   }
152f0f2a8b2STomasz Miąsko   case 'M': {
15306833297STomasz Miąsko     demangleImplPath(InType);
154f0f2a8b2STomasz Miąsko     print("<");
155f0f2a8b2STomasz Miąsko     demangleType();
156f0f2a8b2STomasz Miąsko     print(">");
157f0f2a8b2STomasz Miąsko     break;
158f0f2a8b2STomasz Miąsko   }
1599fa13800STomasz Miąsko   case 'X': {
16006833297STomasz Miąsko     demangleImplPath(InType);
1619fa13800STomasz Miąsko     print("<");
1629fa13800STomasz Miąsko     demangleType();
1639fa13800STomasz Miąsko     print(" as ");
16457f40886STomasz Miąsko     demanglePath(rust_demangle::InType::Yes);
1659fa13800STomasz Miąsko     print(">");
1669fa13800STomasz Miąsko     break;
1679fa13800STomasz Miąsko   }
168f933f7fbSTomasz Miąsko   case 'Y': {
169f933f7fbSTomasz Miąsko     print("<");
170f933f7fbSTomasz Miąsko     demangleType();
171f933f7fbSTomasz Miąsko     print(" as ");
17257f40886STomasz Miąsko     demanglePath(rust_demangle::InType::Yes);
173f933f7fbSTomasz Miąsko     print(">");
174f933f7fbSTomasz Miąsko     break;
175f933f7fbSTomasz Miąsko   }
1767310403eSTomasz Miąsko   case 'N': {
1777310403eSTomasz Miąsko     char NS = consume();
1787310403eSTomasz Miąsko     if (!isLower(NS) && !isUpper(NS)) {
1797310403eSTomasz Miąsko       Error = true;
1807310403eSTomasz Miąsko       break;
1817310403eSTomasz Miąsko     }
18206833297STomasz Miąsko     demanglePath(InType);
1837310403eSTomasz Miąsko 
18478e94915STomasz Miąsko     uint64_t Disambiguator = parseOptionalBase62Number('s');
1857310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1867310403eSTomasz Miąsko 
18778e94915STomasz Miąsko     if (isUpper(NS)) {
18878e94915STomasz Miąsko       // Special namespaces
18978e94915STomasz Miąsko       print("::{");
19078e94915STomasz Miąsko       if (NS == 'C')
19178e94915STomasz Miąsko         print("closure");
19278e94915STomasz Miąsko       else if (NS == 'S')
19378e94915STomasz Miąsko         print("shim");
19478e94915STomasz Miąsko       else
19578e94915STomasz Miąsko         print(NS);
1967310403eSTomasz Miąsko       if (!Ident.empty()) {
19778e94915STomasz Miąsko         print(":");
19878e94915STomasz Miąsko         print(Ident.Name);
19978e94915STomasz Miąsko       }
20078e94915STomasz Miąsko       print('#');
20178e94915STomasz Miąsko       printDecimalNumber(Disambiguator);
20278e94915STomasz Miąsko       print('}');
20378e94915STomasz Miąsko     } else {
20478e94915STomasz Miąsko       // Implementation internal namespaces.
20578e94915STomasz Miąsko       if (!Ident.empty()) {
2067310403eSTomasz Miąsko         print("::");
2077310403eSTomasz Miąsko         print(Ident.Name);
2087310403eSTomasz Miąsko       }
20978e94915STomasz Miąsko     }
2107310403eSTomasz Miąsko     break;
2117310403eSTomasz Miąsko   }
2122961f863STomasz Miąsko   case 'I': {
21306833297STomasz Miąsko     demanglePath(InType);
21406833297STomasz Miąsko     // Omit "::" when in a type, where it is optional.
21557f40886STomasz Miąsko     if (InType == rust_demangle::InType::No)
21606833297STomasz Miąsko       print("::");
21706833297STomasz Miąsko     print("<");
2182961f863STomasz Miąsko     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
2192961f863STomasz Miąsko       if (I > 0)
2202961f863STomasz Miąsko         print(", ");
2212961f863STomasz Miąsko       demangleGenericArg();
2222961f863STomasz Miąsko     }
2232961f863STomasz Miąsko     print(">");
2242961f863STomasz Miąsko     break;
2252961f863STomasz Miąsko   }
2267310403eSTomasz Miąsko   default:
2277310403eSTomasz Miąsko     // FIXME parse remaining productions.
2287310403eSTomasz Miąsko     Error = true;
2297310403eSTomasz Miąsko     break;
2307310403eSTomasz Miąsko   }
2317310403eSTomasz Miąsko }
2327310403eSTomasz Miąsko 
233f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path>
234f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number>
23506833297STomasz Miąsko void Demangler::demangleImplPath(InType InType) {
236f0f2a8b2STomasz Miąsko   SwapAndRestore<bool> SavePrint(Print, false);
237f0f2a8b2STomasz Miąsko   parseOptionalBase62Number('s');
23806833297STomasz Miąsko   demanglePath(InType);
239f0f2a8b2STomasz Miąsko }
240f0f2a8b2STomasz Miąsko 
2412961f863STomasz Miąsko // <generic-arg> = <lifetime>
2422961f863STomasz Miąsko //               | <type>
2432961f863STomasz Miąsko //               | "K" <const>
2442961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
2452961f863STomasz Miąsko void Demangler::demangleGenericArg() {
246*a67a234eSTomasz Miąsko   if (consumeIf('L'))
247*a67a234eSTomasz Miąsko     printLifetime(parseBase62Number());
248*a67a234eSTomasz Miąsko   else if (consumeIf('K'))
249cd74dd17STomasz Miąsko     demangleConst();
250cd74dd17STomasz Miąsko   else
2512961f863STomasz Miąsko     demangleType();
2522961f863STomasz Miąsko }
2532961f863STomasz Miąsko 
2542961f863STomasz Miąsko // <basic-type> = "a"      // i8
2552961f863STomasz Miąsko //              | "b"      // bool
2562961f863STomasz Miąsko //              | "c"      // char
2572961f863STomasz Miąsko //              | "d"      // f64
2582961f863STomasz Miąsko //              | "e"      // str
2592961f863STomasz Miąsko //              | "f"      // f32
2602961f863STomasz Miąsko //              | "h"      // u8
2612961f863STomasz Miąsko //              | "i"      // isize
2622961f863STomasz Miąsko //              | "j"      // usize
2632961f863STomasz Miąsko //              | "l"      // i32
2642961f863STomasz Miąsko //              | "m"      // u32
2652961f863STomasz Miąsko //              | "n"      // i128
2662961f863STomasz Miąsko //              | "o"      // u128
2672961f863STomasz Miąsko //              | "s"      // i16
2682961f863STomasz Miąsko //              | "t"      // u16
2692961f863STomasz Miąsko //              | "u"      // ()
2702961f863STomasz Miąsko //              | "v"      // ...
2712961f863STomasz Miąsko //              | "x"      // i64
2722961f863STomasz Miąsko //              | "y"      // u64
2732961f863STomasz Miąsko //              | "z"      // !
2742961f863STomasz Miąsko //              | "p"      // placeholder (e.g. for generic params), shown as _
275cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
276cd74dd17STomasz Miąsko   switch (C) {
277cd74dd17STomasz Miąsko   case 'a':
278cd74dd17STomasz Miąsko     Type = BasicType::I8;
279cd74dd17STomasz Miąsko     return true;
280cd74dd17STomasz Miąsko   case 'b':
281cd74dd17STomasz Miąsko     Type = BasicType::Bool;
282cd74dd17STomasz Miąsko     return true;
283cd74dd17STomasz Miąsko   case 'c':
284cd74dd17STomasz Miąsko     Type = BasicType::Char;
285cd74dd17STomasz Miąsko     return true;
286cd74dd17STomasz Miąsko   case 'd':
287cd74dd17STomasz Miąsko     Type = BasicType::F64;
288cd74dd17STomasz Miąsko     return true;
289cd74dd17STomasz Miąsko   case 'e':
290cd74dd17STomasz Miąsko     Type = BasicType::Str;
291cd74dd17STomasz Miąsko     return true;
292cd74dd17STomasz Miąsko   case 'f':
293cd74dd17STomasz Miąsko     Type = BasicType::F32;
294cd74dd17STomasz Miąsko     return true;
295cd74dd17STomasz Miąsko   case 'h':
296cd74dd17STomasz Miąsko     Type = BasicType::U8;
297cd74dd17STomasz Miąsko     return true;
298cd74dd17STomasz Miąsko   case 'i':
299cd74dd17STomasz Miąsko     Type = BasicType::ISize;
300cd74dd17STomasz Miąsko     return true;
301cd74dd17STomasz Miąsko   case 'j':
302cd74dd17STomasz Miąsko     Type = BasicType::USize;
303cd74dd17STomasz Miąsko     return true;
304cd74dd17STomasz Miąsko   case 'l':
305cd74dd17STomasz Miąsko     Type = BasicType::I32;
306cd74dd17STomasz Miąsko     return true;
307cd74dd17STomasz Miąsko   case 'm':
308cd74dd17STomasz Miąsko     Type = BasicType::U32;
309cd74dd17STomasz Miąsko     return true;
310cd74dd17STomasz Miąsko   case 'n':
311cd74dd17STomasz Miąsko     Type = BasicType::I128;
312cd74dd17STomasz Miąsko     return true;
313cd74dd17STomasz Miąsko   case 'o':
314cd74dd17STomasz Miąsko     Type = BasicType::U128;
315cd74dd17STomasz Miąsko     return true;
316cd74dd17STomasz Miąsko   case 'p':
317cd74dd17STomasz Miąsko     Type = BasicType::Placeholder;
318cd74dd17STomasz Miąsko     return true;
319cd74dd17STomasz Miąsko   case 's':
320cd74dd17STomasz Miąsko     Type = BasicType::I16;
321cd74dd17STomasz Miąsko     return true;
322cd74dd17STomasz Miąsko   case 't':
323cd74dd17STomasz Miąsko     Type = BasicType::U16;
324cd74dd17STomasz Miąsko     return true;
325cd74dd17STomasz Miąsko   case 'u':
326cd74dd17STomasz Miąsko     Type = BasicType::Unit;
327cd74dd17STomasz Miąsko     return true;
328cd74dd17STomasz Miąsko   case 'v':
329cd74dd17STomasz Miąsko     Type = BasicType::Variadic;
330cd74dd17STomasz Miąsko     return true;
331cd74dd17STomasz Miąsko   case 'x':
332cd74dd17STomasz Miąsko     Type = BasicType::I64;
333cd74dd17STomasz Miąsko     return true;
334cd74dd17STomasz Miąsko   case 'y':
335cd74dd17STomasz Miąsko     Type = BasicType::U64;
336cd74dd17STomasz Miąsko     return true;
337cd74dd17STomasz Miąsko   case 'z':
338cd74dd17STomasz Miąsko     Type = BasicType::Never;
339cd74dd17STomasz Miąsko     return true;
340cd74dd17STomasz Miąsko   default:
341cd74dd17STomasz Miąsko     return false;
342cd74dd17STomasz Miąsko   }
343cd74dd17STomasz Miąsko }
344cd74dd17STomasz Miąsko 
345cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
346cd74dd17STomasz Miąsko   switch (Type) {
347cd74dd17STomasz Miąsko   case BasicType::Bool:
348cd74dd17STomasz Miąsko     print("bool");
349cd74dd17STomasz Miąsko     break;
350cd74dd17STomasz Miąsko   case BasicType::Char:
351cd74dd17STomasz Miąsko     print("char");
352cd74dd17STomasz Miąsko     break;
353cd74dd17STomasz Miąsko   case BasicType::I8:
354cd74dd17STomasz Miąsko     print("i8");
355cd74dd17STomasz Miąsko     break;
356cd74dd17STomasz Miąsko   case BasicType::I16:
357cd74dd17STomasz Miąsko     print("i16");
358cd74dd17STomasz Miąsko     break;
359cd74dd17STomasz Miąsko   case BasicType::I32:
360cd74dd17STomasz Miąsko     print("i32");
361cd74dd17STomasz Miąsko     break;
362cd74dd17STomasz Miąsko   case BasicType::I64:
363cd74dd17STomasz Miąsko     print("i64");
364cd74dd17STomasz Miąsko     break;
365cd74dd17STomasz Miąsko   case BasicType::I128:
366cd74dd17STomasz Miąsko     print("i128");
367cd74dd17STomasz Miąsko     break;
368cd74dd17STomasz Miąsko   case BasicType::ISize:
369cd74dd17STomasz Miąsko     print("isize");
370cd74dd17STomasz Miąsko     break;
371cd74dd17STomasz Miąsko   case BasicType::U8:
372cd74dd17STomasz Miąsko     print("u8");
373cd74dd17STomasz Miąsko     break;
374cd74dd17STomasz Miąsko   case BasicType::U16:
375cd74dd17STomasz Miąsko     print("u16");
376cd74dd17STomasz Miąsko     break;
377cd74dd17STomasz Miąsko   case BasicType::U32:
378cd74dd17STomasz Miąsko     print("u32");
379cd74dd17STomasz Miąsko     break;
380cd74dd17STomasz Miąsko   case BasicType::U64:
381cd74dd17STomasz Miąsko     print("u64");
382cd74dd17STomasz Miąsko     break;
383cd74dd17STomasz Miąsko   case BasicType::U128:
384cd74dd17STomasz Miąsko     print("u128");
385cd74dd17STomasz Miąsko     break;
386cd74dd17STomasz Miąsko   case BasicType::USize:
387cd74dd17STomasz Miąsko     print("usize");
388cd74dd17STomasz Miąsko     break;
389cd74dd17STomasz Miąsko   case BasicType::F32:
390cd74dd17STomasz Miąsko     print("f32");
391cd74dd17STomasz Miąsko     break;
392cd74dd17STomasz Miąsko   case BasicType::F64:
393cd74dd17STomasz Miąsko     print("f64");
394cd74dd17STomasz Miąsko     break;
395cd74dd17STomasz Miąsko   case BasicType::Str:
396cd74dd17STomasz Miąsko     print("str");
397cd74dd17STomasz Miąsko     break;
398cd74dd17STomasz Miąsko   case BasicType::Placeholder:
399cd74dd17STomasz Miąsko     print("_");
400cd74dd17STomasz Miąsko     break;
401cd74dd17STomasz Miąsko   case BasicType::Unit:
402cd74dd17STomasz Miąsko     print("()");
403cd74dd17STomasz Miąsko     break;
404cd74dd17STomasz Miąsko   case BasicType::Variadic:
405cd74dd17STomasz Miąsko     print("...");
406cd74dd17STomasz Miąsko     break;
407cd74dd17STomasz Miąsko   case BasicType::Never:
408cd74dd17STomasz Miąsko     print("!");
409cd74dd17STomasz Miąsko     break;
410cd74dd17STomasz Miąsko   }
4112961f863STomasz Miąsko }
4122961f863STomasz Miąsko 
4132961f863STomasz Miąsko // <type> = | <basic-type>
4142961f863STomasz Miąsko //          | <path>                      // named type
4152961f863STomasz Miąsko //          | "A" <type> <const>          // [T; N]
4162961f863STomasz Miąsko //          | "S" <type>                  // [T]
4172961f863STomasz Miąsko //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
4182961f863STomasz Miąsko //          | "R" [<lifetime>] <type>     // &T
4192961f863STomasz Miąsko //          | "Q" [<lifetime>] <type>     // &mut T
4202961f863STomasz Miąsko //          | "P" <type>                  // *const T
4212961f863STomasz Miąsko //          | "O" <type>                  // *mut T
4222961f863STomasz Miąsko //          | "F" <fn-sig>                // fn(...) -> ...
4232961f863STomasz Miąsko //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
4242961f863STomasz Miąsko //          | <backref>                   // backref
4252961f863STomasz Miąsko void Demangler::demangleType() {
426b42400ccSTomasz Miąsko   size_t Start = Position;
42706833297STomasz Miąsko 
428b42400ccSTomasz Miąsko   char C = consume();
429b42400ccSTomasz Miąsko   BasicType Type;
430b42400ccSTomasz Miąsko   if (parseBasicType(C, Type))
431b42400ccSTomasz Miąsko     return printBasicType(Type);
432b42400ccSTomasz Miąsko 
433b42400ccSTomasz Miąsko   switch (C) {
434b42400ccSTomasz Miąsko   case 'A':
435b42400ccSTomasz Miąsko     print("[");
436b42400ccSTomasz Miąsko     demangleType();
437b42400ccSTomasz Miąsko     print("; ");
438b42400ccSTomasz Miąsko     demangleConst();
439b42400ccSTomasz Miąsko     print("]");
440b42400ccSTomasz Miąsko     break;
441a84c65c2STomasz Miąsko   case 'S':
442a84c65c2STomasz Miąsko     print("[");
443a84c65c2STomasz Miąsko     demangleType();
444a84c65c2STomasz Miąsko     print("]");
445a84c65c2STomasz Miąsko     break;
446774de7a0STomasz Miąsko   case 'T': {
447774de7a0STomasz Miąsko     print("(");
448774de7a0STomasz Miąsko     size_t I = 0;
449774de7a0STomasz Miąsko     for (; !Error && !consumeIf('E'); ++I) {
450774de7a0STomasz Miąsko       if (I > 0)
451774de7a0STomasz Miąsko         print(", ");
452774de7a0STomasz Miąsko       demangleType();
453774de7a0STomasz Miąsko     }
454774de7a0STomasz Miąsko     if (I == 1)
455774de7a0STomasz Miąsko       print(",");
456774de7a0STomasz Miąsko     print(")");
457774de7a0STomasz Miąsko     break;
458774de7a0STomasz Miąsko   }
459e4fa6c95STomasz Miąsko   case 'R':
460e4fa6c95STomasz Miąsko   case 'Q':
461*a67a234eSTomasz Miąsko     print('&');
462*a67a234eSTomasz Miąsko     if (consumeIf('L')) {
463*a67a234eSTomasz Miąsko       if (auto Lifetime = parseBase62Number()) {
464*a67a234eSTomasz Miąsko         printLifetime(Lifetime);
465*a67a234eSTomasz Miąsko         print(' ');
466*a67a234eSTomasz Miąsko       }
467*a67a234eSTomasz Miąsko     }
468*a67a234eSTomasz Miąsko     if (C == 'Q')
469*a67a234eSTomasz Miąsko       print("mut ");
470e4fa6c95STomasz Miąsko     demangleType();
471e4fa6c95STomasz Miąsko     break;
4726aac5633STomasz Miąsko   case 'P':
4736aac5633STomasz Miąsko     print("*const ");
4746aac5633STomasz Miąsko     demangleType();
4756aac5633STomasz Miąsko     break;
4766aac5633STomasz Miąsko   case 'O':
4776aac5633STomasz Miąsko     print("*mut ");
4786aac5633STomasz Miąsko     demangleType();
4796aac5633STomasz Miąsko     break;
48075cc1cf0STomasz Miąsko   case 'F':
48175cc1cf0STomasz Miąsko     demangleFnSig();
48275cc1cf0STomasz Miąsko     break;
483b42400ccSTomasz Miąsko   default:
484b42400ccSTomasz Miąsko     Position = Start;
48557f40886STomasz Miąsko     demanglePath(rust_demangle::InType::Yes);
486b42400ccSTomasz Miąsko     break;
487b42400ccSTomasz Miąsko   }
488cd74dd17STomasz Miąsko }
489cd74dd17STomasz Miąsko 
49075cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
49175cc1cf0STomasz Miąsko // <abi> = "C"
49275cc1cf0STomasz Miąsko //       | <undisambiguated-identifier>
49375cc1cf0STomasz Miąsko void Demangler::demangleFnSig() {
494*a67a234eSTomasz Miąsko   SwapAndRestore<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
495*a67a234eSTomasz Miąsko   demangleOptionalBinder();
49675cc1cf0STomasz Miąsko 
49775cc1cf0STomasz Miąsko   if (consumeIf('U'))
49875cc1cf0STomasz Miąsko     print("unsafe ");
49975cc1cf0STomasz Miąsko 
50075cc1cf0STomasz Miąsko   if (consumeIf('K')) {
50175cc1cf0STomasz Miąsko     print("extern \"");
50275cc1cf0STomasz Miąsko     if (consumeIf('C')) {
50375cc1cf0STomasz Miąsko       print("C");
50475cc1cf0STomasz Miąsko     } else {
50575cc1cf0STomasz Miąsko       Identifier Ident = parseIdentifier();
50675cc1cf0STomasz Miąsko       for (char C : Ident.Name) {
50775cc1cf0STomasz Miąsko         // When mangling ABI string, the "-" is replaced with "_".
50875cc1cf0STomasz Miąsko         if (C == '_')
50975cc1cf0STomasz Miąsko           C = '-';
51075cc1cf0STomasz Miąsko         print(C);
51175cc1cf0STomasz Miąsko       }
51275cc1cf0STomasz Miąsko     }
51375cc1cf0STomasz Miąsko     print("\" ");
51475cc1cf0STomasz Miąsko   }
51575cc1cf0STomasz Miąsko 
51675cc1cf0STomasz Miąsko   print("fn(");
51775cc1cf0STomasz Miąsko   for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
51875cc1cf0STomasz Miąsko     if (I > 0)
51975cc1cf0STomasz Miąsko       print(", ");
52075cc1cf0STomasz Miąsko     demangleType();
52175cc1cf0STomasz Miąsko   }
52275cc1cf0STomasz Miąsko   print(")");
52375cc1cf0STomasz Miąsko 
52475cc1cf0STomasz Miąsko   if (consumeIf('u')) {
52575cc1cf0STomasz Miąsko     // Skip the unit type from the output.
52675cc1cf0STomasz Miąsko   } else {
52775cc1cf0STomasz Miąsko     print(" -> ");
52875cc1cf0STomasz Miąsko     demangleType();
52975cc1cf0STomasz Miąsko   }
53075cc1cf0STomasz Miąsko }
53175cc1cf0STomasz Miąsko 
532*a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes.
533*a67a234eSTomasz Miąsko //
534*a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number>
535*a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() {
536*a67a234eSTomasz Miąsko   uint64_t Binder = parseOptionalBase62Number('G');
537*a67a234eSTomasz Miąsko   if (Error || Binder == 0)
538*a67a234eSTomasz Miąsko     return;
539*a67a234eSTomasz Miąsko 
540*a67a234eSTomasz Miąsko   // In valid inputs each bound lifetime is referenced later. Referencing a
541*a67a234eSTomasz Miąsko   // lifetime requires at least one byte of input. Reject inputs that are too
542*a67a234eSTomasz Miąsko   // short to reference all bound lifetimes. Otherwise demangling of invalid
543*a67a234eSTomasz Miąsko   // binders could generate excessive amounts of output.
544*a67a234eSTomasz Miąsko   if (Binder >= Input.size() - BoundLifetimes) {
545*a67a234eSTomasz Miąsko     Error = true;
546*a67a234eSTomasz Miąsko     return;
547*a67a234eSTomasz Miąsko   }
548*a67a234eSTomasz Miąsko 
549*a67a234eSTomasz Miąsko   print("for<");
550*a67a234eSTomasz Miąsko   for (size_t I = 0; I != Binder; ++I) {
551*a67a234eSTomasz Miąsko     BoundLifetimes += 1;
552*a67a234eSTomasz Miąsko     if (I > 0)
553*a67a234eSTomasz Miąsko       print(", ");
554*a67a234eSTomasz Miąsko     printLifetime(1);
555*a67a234eSTomasz Miąsko   }
556*a67a234eSTomasz Miąsko   print("> ");
557*a67a234eSTomasz Miąsko }
558*a67a234eSTomasz Miąsko 
559cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
560cd74dd17STomasz Miąsko //         | "p"                          // placeholder
561cd74dd17STomasz Miąsko //         | <backref>
562cd74dd17STomasz Miąsko void Demangler::demangleConst() {
563cd74dd17STomasz Miąsko   BasicType Type;
564cd74dd17STomasz Miąsko   if (parseBasicType(consume(), Type)) {
565cd74dd17STomasz Miąsko     switch (Type) {
566cd74dd17STomasz Miąsko     case BasicType::I8:
567cd74dd17STomasz Miąsko     case BasicType::I16:
568cd74dd17STomasz Miąsko     case BasicType::I32:
569cd74dd17STomasz Miąsko     case BasicType::I64:
570cd74dd17STomasz Miąsko     case BasicType::I128:
571cd74dd17STomasz Miąsko     case BasicType::ISize:
572cd74dd17STomasz Miąsko     case BasicType::U8:
573cd74dd17STomasz Miąsko     case BasicType::U16:
574cd74dd17STomasz Miąsko     case BasicType::U32:
575cd74dd17STomasz Miąsko     case BasicType::U64:
576cd74dd17STomasz Miąsko     case BasicType::U128:
577cd74dd17STomasz Miąsko     case BasicType::USize:
578cd74dd17STomasz Miąsko       demangleConstInt();
579cd74dd17STomasz Miąsko       break;
580fc0f2bb9STomasz Miąsko     case BasicType::Bool:
581fc0f2bb9STomasz Miąsko       demangleConstBool();
582fc0f2bb9STomasz Miąsko       break;
5832ba49f6aSTomasz Miąsko     case BasicType::Char:
5842ba49f6aSTomasz Miąsko       demangleConstChar();
5852ba49f6aSTomasz Miąsko       break;
586cd74dd17STomasz Miąsko     case BasicType::Placeholder:
587cd74dd17STomasz Miąsko       print('_');
588cd74dd17STomasz Miąsko       break;
589cd74dd17STomasz Miąsko     default:
5902ba49f6aSTomasz Miąsko       // FIXME demangle backreferences.
5912961f863STomasz Miąsko       Error = true;
592cd74dd17STomasz Miąsko       break;
593cd74dd17STomasz Miąsko     }
594cd74dd17STomasz Miąsko   } else {
595cd74dd17STomasz Miąsko     Error = true;
596cd74dd17STomasz Miąsko   }
597cd74dd17STomasz Miąsko }
598cd74dd17STomasz Miąsko 
599cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
600cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
601cd74dd17STomasz Miąsko   if (consumeIf('n'))
602cd74dd17STomasz Miąsko     print('-');
603cd74dd17STomasz Miąsko 
604cd74dd17STomasz Miąsko   StringView HexDigits;
605cd74dd17STomasz Miąsko   uint64_t Value = parseHexNumber(HexDigits);
606cd74dd17STomasz Miąsko   if (HexDigits.size() <= 16) {
607cd74dd17STomasz Miąsko     printDecimalNumber(Value);
608cd74dd17STomasz Miąsko   } else {
609cd74dd17STomasz Miąsko     print("0x");
610cd74dd17STomasz Miąsko     print(HexDigits);
6112961f863STomasz Miąsko   }
6122961f863STomasz Miąsko }
6132961f863STomasz Miąsko 
614fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
615fc0f2bb9STomasz Miąsko //              | "1_" // true
616fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
617fc0f2bb9STomasz Miąsko   StringView HexDigits;
618fc0f2bb9STomasz Miąsko   parseHexNumber(HexDigits);
619fc0f2bb9STomasz Miąsko   if (HexDigits == "0")
620fc0f2bb9STomasz Miąsko     print("false");
621fc0f2bb9STomasz Miąsko   else if (HexDigits == "1")
622fc0f2bb9STomasz Miąsko     print("true");
623fc0f2bb9STomasz Miąsko   else
624fc0f2bb9STomasz Miąsko     Error = true;
625fc0f2bb9STomasz Miąsko }
626fc0f2bb9STomasz Miąsko 
6272ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character.
6282ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) {
6292ba49f6aSTomasz Miąsko   return 0x20 <= CodePoint && CodePoint <= 0x7e;
6302ba49f6aSTomasz Miąsko }
6312ba49f6aSTomasz Miąsko 
6322ba49f6aSTomasz Miąsko // <const-data> = <hex-number>
6332ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() {
6342ba49f6aSTomasz Miąsko   StringView HexDigits;
6352ba49f6aSTomasz Miąsko   uint64_t CodePoint = parseHexNumber(HexDigits);
6362ba49f6aSTomasz Miąsko   if (Error || HexDigits.size() > 6) {
6372ba49f6aSTomasz Miąsko     Error = true;
6382ba49f6aSTomasz Miąsko     return;
6392ba49f6aSTomasz Miąsko   }
6402ba49f6aSTomasz Miąsko 
6412ba49f6aSTomasz Miąsko   print("'");
6422ba49f6aSTomasz Miąsko   switch (CodePoint) {
6432ba49f6aSTomasz Miąsko   case '\t':
6442ba49f6aSTomasz Miąsko     print(R"(\t)");
6452ba49f6aSTomasz Miąsko     break;
6462ba49f6aSTomasz Miąsko   case '\r':
6472ba49f6aSTomasz Miąsko     print(R"(\r)");
6482ba49f6aSTomasz Miąsko     break;
6492ba49f6aSTomasz Miąsko   case '\n':
6502ba49f6aSTomasz Miąsko     print(R"(\n)");
6512ba49f6aSTomasz Miąsko     break;
6522ba49f6aSTomasz Miąsko   case '\\':
6532ba49f6aSTomasz Miąsko     print(R"(\\)");
6542ba49f6aSTomasz Miąsko     break;
6552ba49f6aSTomasz Miąsko   case '"':
6562ba49f6aSTomasz Miąsko     print(R"(")");
6572ba49f6aSTomasz Miąsko     break;
6582ba49f6aSTomasz Miąsko   case '\'':
6592ba49f6aSTomasz Miąsko     print(R"(\')");
6602ba49f6aSTomasz Miąsko     break;
6612ba49f6aSTomasz Miąsko   default:
6622ba49f6aSTomasz Miąsko     if (isAsciiPrintable(CodePoint)) {
6632ba49f6aSTomasz Miąsko       char C = CodePoint;
6642ba49f6aSTomasz Miąsko       print(C);
6652ba49f6aSTomasz Miąsko     } else {
6662ba49f6aSTomasz Miąsko       print(R"(\u{)");
6672ba49f6aSTomasz Miąsko       print(HexDigits);
6682ba49f6aSTomasz Miąsko       print('}');
6692ba49f6aSTomasz Miąsko     }
6702ba49f6aSTomasz Miąsko     break;
6712ba49f6aSTomasz Miąsko   }
6722ba49f6aSTomasz Miąsko   print('\'');
6732ba49f6aSTomasz Miąsko }
6742ba49f6aSTomasz Miąsko 
6757310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
6767310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
6777310403eSTomasz Miąsko   bool Punycode = consumeIf('u');
6787310403eSTomasz Miąsko   uint64_t Bytes = parseDecimalNumber();
6797310403eSTomasz Miąsko 
6807310403eSTomasz Miąsko   // Underscore resolves the ambiguity when identifier starts with a decimal
6817310403eSTomasz Miąsko   // digit or another underscore.
6827310403eSTomasz Miąsko   consumeIf('_');
6837310403eSTomasz Miąsko 
6847310403eSTomasz Miąsko   if (Error || Bytes > Input.size() - Position) {
6857310403eSTomasz Miąsko     Error = true;
6867310403eSTomasz Miąsko     return {};
6877310403eSTomasz Miąsko   }
6887310403eSTomasz Miąsko   StringView S = Input.substr(Position, Bytes);
6897310403eSTomasz Miąsko   Position += Bytes;
6907310403eSTomasz Miąsko 
6917310403eSTomasz Miąsko   if (!std::all_of(S.begin(), S.end(), isValid)) {
6927310403eSTomasz Miąsko     Error = true;
6937310403eSTomasz Miąsko     return {};
6947310403eSTomasz Miąsko   }
6957310403eSTomasz Miąsko 
6967310403eSTomasz Miąsko   return {S, Punycode};
6977310403eSTomasz Miąsko }
6987310403eSTomasz Miąsko 
6997310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
700*a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
701*a67a234eSTomasz Miąsko //
702*a67a234eSTomasz Miąsko // This function is indended for parsing disambiguators and binders which when
703*a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded
704*a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
705*a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0.
70678e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
70778e94915STomasz Miąsko   if (!consumeIf(Tag))
70878e94915STomasz Miąsko     return 0;
70978e94915STomasz Miąsko 
71078e94915STomasz Miąsko   uint64_t N = parseBase62Number();
71178e94915STomasz Miąsko   if (Error || !addAssign(N, 1))
71278e94915STomasz Miąsko     return 0;
71378e94915STomasz Miąsko 
71478e94915STomasz Miąsko   return N;
7157310403eSTomasz Miąsko }
7167310403eSTomasz Miąsko 
7177310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
7187310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
7197310403eSTomasz Miąsko // "1_" encodes 2, etc.
7207310403eSTomasz Miąsko //
7217310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
7227310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
7237310403eSTomasz Miąsko   if (consumeIf('_'))
7247310403eSTomasz Miąsko     return 0;
7257310403eSTomasz Miąsko 
7267310403eSTomasz Miąsko   uint64_t Value = 0;
7277310403eSTomasz Miąsko 
7287310403eSTomasz Miąsko   while (true) {
7297310403eSTomasz Miąsko     uint64_t Digit;
7307310403eSTomasz Miąsko     char C = consume();
7317310403eSTomasz Miąsko 
7327310403eSTomasz Miąsko     if (C == '_') {
7337310403eSTomasz Miąsko       break;
7347310403eSTomasz Miąsko     } else if (isDigit(C)) {
7357310403eSTomasz Miąsko       Digit = C - '0';
7367310403eSTomasz Miąsko     } else if (isLower(C)) {
7377310403eSTomasz Miąsko       Digit = 10 + (C - 'a');
7387310403eSTomasz Miąsko     } else if (isUpper(C)) {
7397310403eSTomasz Miąsko       Digit = 10 + 26 + (C - 'A');
7407310403eSTomasz Miąsko     } else {
7417310403eSTomasz Miąsko       Error = true;
7427310403eSTomasz Miąsko       return 0;
7437310403eSTomasz Miąsko     }
7447310403eSTomasz Miąsko 
7457310403eSTomasz Miąsko     if (!mulAssign(Value, 62))
7467310403eSTomasz Miąsko       return 0;
7477310403eSTomasz Miąsko 
7487310403eSTomasz Miąsko     if (!addAssign(Value, Digit))
7497310403eSTomasz Miąsko       return 0;
7507310403eSTomasz Miąsko   }
7517310403eSTomasz Miąsko 
7527310403eSTomasz Miąsko   if (!addAssign(Value, 1))
7537310403eSTomasz Miąsko     return 0;
7547310403eSTomasz Miąsko 
7557310403eSTomasz Miąsko   return Value;
7567310403eSTomasz Miąsko }
7577310403eSTomasz Miąsko 
7587310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
7597310403eSTomasz Miąsko //
7607310403eSTomasz Miąsko // <decimal-number> = "0"
7617310403eSTomasz Miąsko //                  | <1-9> {<0-9>}
7627310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
7637310403eSTomasz Miąsko   char C = look();
7647310403eSTomasz Miąsko   if (!isDigit(C)) {
7657310403eSTomasz Miąsko     Error = true;
7667310403eSTomasz Miąsko     return 0;
7677310403eSTomasz Miąsko   }
7687310403eSTomasz Miąsko 
7697310403eSTomasz Miąsko   if (C == '0') {
7707310403eSTomasz Miąsko     consume();
7717310403eSTomasz Miąsko     return 0;
7727310403eSTomasz Miąsko   }
7737310403eSTomasz Miąsko 
7747310403eSTomasz Miąsko   uint64_t Value = 0;
7757310403eSTomasz Miąsko 
7767310403eSTomasz Miąsko   while (isDigit(look())) {
7777310403eSTomasz Miąsko     if (!mulAssign(Value, 10)) {
7787310403eSTomasz Miąsko       Error = true;
7797310403eSTomasz Miąsko       return 0;
7807310403eSTomasz Miąsko     }
7817310403eSTomasz Miąsko 
7827310403eSTomasz Miąsko     uint64_t D = consume() - '0';
7837310403eSTomasz Miąsko     if (!addAssign(Value, D))
7847310403eSTomasz Miąsko       return 0;
7857310403eSTomasz Miąsko   }
7867310403eSTomasz Miąsko 
7877310403eSTomasz Miąsko   return Value;
7887310403eSTomasz Miąsko }
789cd74dd17STomasz Miąsko 
790cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
791cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
792cd74dd17STomasz Miąsko // HexDigits.size() > 16.
793cd74dd17STomasz Miąsko //
794cd74dd17STomasz Miąsko // <hex-number> = "0_"
795cd74dd17STomasz Miąsko //              | <1-9a-f> {<0-9a-f>} "_"
796cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
797cd74dd17STomasz Miąsko   size_t Start = Position;
798cd74dd17STomasz Miąsko   uint64_t Value = 0;
799cd74dd17STomasz Miąsko 
800cd74dd17STomasz Miąsko   if (!isHexDigit(look()))
801cd74dd17STomasz Miąsko     Error = true;
802cd74dd17STomasz Miąsko 
803cd74dd17STomasz Miąsko   if (consumeIf('0')) {
804cd74dd17STomasz Miąsko     if (!consumeIf('_'))
805cd74dd17STomasz Miąsko       Error = true;
806cd74dd17STomasz Miąsko   } else {
807cd74dd17STomasz Miąsko     while (!Error && !consumeIf('_')) {
808cd74dd17STomasz Miąsko       char C = consume();
809cd74dd17STomasz Miąsko       Value *= 16;
810cd74dd17STomasz Miąsko       if (isDigit(C))
811cd74dd17STomasz Miąsko         Value += C - '0';
812cd74dd17STomasz Miąsko       else if ('a' <= C && C <= 'f')
813cd74dd17STomasz Miąsko         Value += 10 + (C - 'a');
814cd74dd17STomasz Miąsko       else
815cd74dd17STomasz Miąsko         Error = true;
816cd74dd17STomasz Miąsko     }
817cd74dd17STomasz Miąsko   }
818cd74dd17STomasz Miąsko 
819cd74dd17STomasz Miąsko   if (Error) {
820cd74dd17STomasz Miąsko     HexDigits = StringView();
821cd74dd17STomasz Miąsko     return 0;
822cd74dd17STomasz Miąsko   }
823cd74dd17STomasz Miąsko 
824cd74dd17STomasz Miąsko   size_t End = Position - 1;
825cd74dd17STomasz Miąsko   assert(Start < End);
826cd74dd17STomasz Miąsko   HexDigits = Input.substr(Start, End - Start);
827cd74dd17STomasz Miąsko   return Value;
828cd74dd17STomasz Miąsko }
829*a67a234eSTomasz Miąsko 
830*a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
831*a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
832*a67a234eSTomasz Miąsko // bound by one of the enclosing binders.
833*a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) {
834*a67a234eSTomasz Miąsko   if (Index == 0) {
835*a67a234eSTomasz Miąsko     print("'_");
836*a67a234eSTomasz Miąsko     return;
837*a67a234eSTomasz Miąsko   }
838*a67a234eSTomasz Miąsko 
839*a67a234eSTomasz Miąsko   if (Index - 1 >= BoundLifetimes) {
840*a67a234eSTomasz Miąsko     Error = true;
841*a67a234eSTomasz Miąsko     return;
842*a67a234eSTomasz Miąsko   }
843*a67a234eSTomasz Miąsko 
844*a67a234eSTomasz Miąsko   uint64_t Depth = BoundLifetimes - Index;
845*a67a234eSTomasz Miąsko   print('\'');
846*a67a234eSTomasz Miąsko   if (Depth < 26) {
847*a67a234eSTomasz Miąsko     char C = 'a' + Depth;
848*a67a234eSTomasz Miąsko     print(C);
849*a67a234eSTomasz Miąsko   } else {
850*a67a234eSTomasz Miąsko     print('z');
851*a67a234eSTomasz Miąsko     printDecimalNumber(Depth - 26 + 1);
852*a67a234eSTomasz Miąsko   }
853*a67a234eSTomasz Miąsko }
854