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;
1047310403eSTomasz Miąsko   RecursionLevel = 0;
1057310403eSTomasz Miąsko 
1067310403eSTomasz Miąsko   if (!Mangled.consumeFront("_R")) {
1077310403eSTomasz Miąsko     Error = true;
1087310403eSTomasz Miąsko     return false;
1097310403eSTomasz Miąsko   }
1107310403eSTomasz Miąsko   Input = Mangled;
1117310403eSTomasz Miąsko 
1127310403eSTomasz Miąsko   demanglePath();
1137310403eSTomasz Miąsko 
1147310403eSTomasz Miąsko   // FIXME parse optional <instantiating-crate>.
1157310403eSTomasz Miąsko 
1167310403eSTomasz Miąsko   if (Position != Input.size())
1177310403eSTomasz Miąsko     Error = true;
1187310403eSTomasz Miąsko 
1197310403eSTomasz Miąsko   return !Error;
1207310403eSTomasz Miąsko }
1217310403eSTomasz Miąsko 
1227310403eSTomasz Miąsko // <path> = "C" <identifier>               // crate root
1237310403eSTomasz Miąsko //        | "M" <impl-path> <type>         // <T> (inherent impl)
1247310403eSTomasz Miąsko //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
1257310403eSTomasz Miąsko //        | "Y" <type> <path>              // <T as Trait> (trait definition)
1267310403eSTomasz Miąsko //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
1277310403eSTomasz Miąsko //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
1287310403eSTomasz Miąsko //        | <backref>
1297310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
1307310403eSTomasz Miąsko // <ns> = "C"      // closure
1317310403eSTomasz Miąsko //      | "S"      // shim
1327310403eSTomasz Miąsko //      | <A-Z>    // other special namespaces
1337310403eSTomasz Miąsko //      | <a-z>    // internal namespaces
1347310403eSTomasz Miąsko void Demangler::demanglePath() {
1357310403eSTomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
1367310403eSTomasz Miąsko     Error = true;
1377310403eSTomasz Miąsko     return;
1387310403eSTomasz Miąsko   }
13978e94915STomasz Miąsko   SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
1407310403eSTomasz Miąsko 
1417310403eSTomasz Miąsko   switch (consume()) {
1427310403eSTomasz Miąsko   case 'C': {
1437310403eSTomasz Miąsko     parseOptionalBase62Number('s');
1447310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1457310403eSTomasz Miąsko     print(Ident.Name);
1467310403eSTomasz Miąsko     break;
1477310403eSTomasz Miąsko   }
1487310403eSTomasz Miąsko   case 'N': {
1497310403eSTomasz Miąsko     char NS = consume();
1507310403eSTomasz Miąsko     if (!isLower(NS) && !isUpper(NS)) {
1517310403eSTomasz Miąsko       Error = true;
1527310403eSTomasz Miąsko       break;
1537310403eSTomasz Miąsko     }
1547310403eSTomasz Miąsko     demanglePath();
1557310403eSTomasz Miąsko 
15678e94915STomasz Miąsko     uint64_t Disambiguator = parseOptionalBase62Number('s');
1577310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1587310403eSTomasz Miąsko 
15978e94915STomasz Miąsko     if (isUpper(NS)) {
16078e94915STomasz Miąsko       // Special namespaces
16178e94915STomasz Miąsko       print("::{");
16278e94915STomasz Miąsko       if (NS == 'C')
16378e94915STomasz Miąsko         print("closure");
16478e94915STomasz Miąsko       else if (NS == 'S')
16578e94915STomasz Miąsko         print("shim");
16678e94915STomasz Miąsko       else
16778e94915STomasz Miąsko         print(NS);
1687310403eSTomasz Miąsko       if (!Ident.empty()) {
16978e94915STomasz Miąsko         print(":");
17078e94915STomasz Miąsko         print(Ident.Name);
17178e94915STomasz Miąsko       }
17278e94915STomasz Miąsko       print('#');
17378e94915STomasz Miąsko       printDecimalNumber(Disambiguator);
17478e94915STomasz Miąsko       print('}');
17578e94915STomasz Miąsko     } else {
17678e94915STomasz Miąsko       // Implementation internal namespaces.
17778e94915STomasz Miąsko       if (!Ident.empty()) {
1787310403eSTomasz Miąsko         print("::");
1797310403eSTomasz Miąsko         print(Ident.Name);
1807310403eSTomasz Miąsko       }
18178e94915STomasz Miąsko     }
1827310403eSTomasz Miąsko     break;
1837310403eSTomasz Miąsko   }
1842961f863STomasz Miąsko   case 'I': {
1852961f863STomasz Miąsko     demanglePath();
1862961f863STomasz Miąsko     print("::<");
1872961f863STomasz Miąsko     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
1882961f863STomasz Miąsko       if (I > 0)
1892961f863STomasz Miąsko         print(", ");
1902961f863STomasz Miąsko       demangleGenericArg();
1912961f863STomasz Miąsko     }
1922961f863STomasz Miąsko     print(">");
1932961f863STomasz Miąsko     break;
1942961f863STomasz Miąsko   }
1957310403eSTomasz Miąsko   default:
1967310403eSTomasz Miąsko     // FIXME parse remaining productions.
1977310403eSTomasz Miąsko     Error = true;
1987310403eSTomasz Miąsko     break;
1997310403eSTomasz Miąsko   }
2007310403eSTomasz Miąsko }
2017310403eSTomasz Miąsko 
2022961f863STomasz Miąsko // <generic-arg> = <lifetime>
2032961f863STomasz Miąsko //               | <type>
2042961f863STomasz Miąsko //               | "K" <const>
2052961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
2062961f863STomasz Miąsko void Demangler::demangleGenericArg() {
207cd74dd17STomasz Miąsko   if (consumeIf('K'))
208cd74dd17STomasz Miąsko     demangleConst();
209cd74dd17STomasz Miąsko   else
2102961f863STomasz Miąsko     demangleType();
211cd74dd17STomasz Miąsko   // FIXME demangle lifetimes.
2122961f863STomasz Miąsko }
2132961f863STomasz Miąsko 
2142961f863STomasz Miąsko // <basic-type> = "a"      // i8
2152961f863STomasz Miąsko //              | "b"      // bool
2162961f863STomasz Miąsko //              | "c"      // char
2172961f863STomasz Miąsko //              | "d"      // f64
2182961f863STomasz Miąsko //              | "e"      // str
2192961f863STomasz Miąsko //              | "f"      // f32
2202961f863STomasz Miąsko //              | "h"      // u8
2212961f863STomasz Miąsko //              | "i"      // isize
2222961f863STomasz Miąsko //              | "j"      // usize
2232961f863STomasz Miąsko //              | "l"      // i32
2242961f863STomasz Miąsko //              | "m"      // u32
2252961f863STomasz Miąsko //              | "n"      // i128
2262961f863STomasz Miąsko //              | "o"      // u128
2272961f863STomasz Miąsko //              | "s"      // i16
2282961f863STomasz Miąsko //              | "t"      // u16
2292961f863STomasz Miąsko //              | "u"      // ()
2302961f863STomasz Miąsko //              | "v"      // ...
2312961f863STomasz Miąsko //              | "x"      // i64
2322961f863STomasz Miąsko //              | "y"      // u64
2332961f863STomasz Miąsko //              | "z"      // !
2342961f863STomasz Miąsko //              | "p"      // placeholder (e.g. for generic params), shown as _
235cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
236cd74dd17STomasz Miąsko   switch (C) {
237cd74dd17STomasz Miąsko   case 'a':
238cd74dd17STomasz Miąsko     Type = BasicType::I8;
239cd74dd17STomasz Miąsko     return true;
240cd74dd17STomasz Miąsko   case 'b':
241cd74dd17STomasz Miąsko     Type = BasicType::Bool;
242cd74dd17STomasz Miąsko     return true;
243cd74dd17STomasz Miąsko   case 'c':
244cd74dd17STomasz Miąsko     Type = BasicType::Char;
245cd74dd17STomasz Miąsko     return true;
246cd74dd17STomasz Miąsko   case 'd':
247cd74dd17STomasz Miąsko     Type = BasicType::F64;
248cd74dd17STomasz Miąsko     return true;
249cd74dd17STomasz Miąsko   case 'e':
250cd74dd17STomasz Miąsko     Type = BasicType::Str;
251cd74dd17STomasz Miąsko     return true;
252cd74dd17STomasz Miąsko   case 'f':
253cd74dd17STomasz Miąsko     Type = BasicType::F32;
254cd74dd17STomasz Miąsko     return true;
255cd74dd17STomasz Miąsko   case 'h':
256cd74dd17STomasz Miąsko     Type = BasicType::U8;
257cd74dd17STomasz Miąsko     return true;
258cd74dd17STomasz Miąsko   case 'i':
259cd74dd17STomasz Miąsko     Type = BasicType::ISize;
260cd74dd17STomasz Miąsko     return true;
261cd74dd17STomasz Miąsko   case 'j':
262cd74dd17STomasz Miąsko     Type = BasicType::USize;
263cd74dd17STomasz Miąsko     return true;
264cd74dd17STomasz Miąsko   case 'l':
265cd74dd17STomasz Miąsko     Type = BasicType::I32;
266cd74dd17STomasz Miąsko     return true;
267cd74dd17STomasz Miąsko   case 'm':
268cd74dd17STomasz Miąsko     Type = BasicType::U32;
269cd74dd17STomasz Miąsko     return true;
270cd74dd17STomasz Miąsko   case 'n':
271cd74dd17STomasz Miąsko     Type = BasicType::I128;
272cd74dd17STomasz Miąsko     return true;
273cd74dd17STomasz Miąsko   case 'o':
274cd74dd17STomasz Miąsko     Type = BasicType::U128;
275cd74dd17STomasz Miąsko     return true;
276cd74dd17STomasz Miąsko   case 'p':
277cd74dd17STomasz Miąsko     Type = BasicType::Placeholder;
278cd74dd17STomasz Miąsko     return true;
279cd74dd17STomasz Miąsko   case 's':
280cd74dd17STomasz Miąsko     Type = BasicType::I16;
281cd74dd17STomasz Miąsko     return true;
282cd74dd17STomasz Miąsko   case 't':
283cd74dd17STomasz Miąsko     Type = BasicType::U16;
284cd74dd17STomasz Miąsko     return true;
285cd74dd17STomasz Miąsko   case 'u':
286cd74dd17STomasz Miąsko     Type = BasicType::Unit;
287cd74dd17STomasz Miąsko     return true;
288cd74dd17STomasz Miąsko   case 'v':
289cd74dd17STomasz Miąsko     Type = BasicType::Variadic;
290cd74dd17STomasz Miąsko     return true;
291cd74dd17STomasz Miąsko   case 'x':
292cd74dd17STomasz Miąsko     Type = BasicType::I64;
293cd74dd17STomasz Miąsko     return true;
294cd74dd17STomasz Miąsko   case 'y':
295cd74dd17STomasz Miąsko     Type = BasicType::U64;
296cd74dd17STomasz Miąsko     return true;
297cd74dd17STomasz Miąsko   case 'z':
298cd74dd17STomasz Miąsko     Type = BasicType::Never;
299cd74dd17STomasz Miąsko     return true;
300cd74dd17STomasz Miąsko   default:
301cd74dd17STomasz Miąsko     return false;
302cd74dd17STomasz Miąsko   }
303cd74dd17STomasz Miąsko }
304cd74dd17STomasz Miąsko 
305cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
306cd74dd17STomasz Miąsko   switch (Type) {
307cd74dd17STomasz Miąsko   case BasicType::Bool:
308cd74dd17STomasz Miąsko     print("bool");
309cd74dd17STomasz Miąsko     break;
310cd74dd17STomasz Miąsko   case BasicType::Char:
311cd74dd17STomasz Miąsko     print("char");
312cd74dd17STomasz Miąsko     break;
313cd74dd17STomasz Miąsko   case BasicType::I8:
314cd74dd17STomasz Miąsko     print("i8");
315cd74dd17STomasz Miąsko     break;
316cd74dd17STomasz Miąsko   case BasicType::I16:
317cd74dd17STomasz Miąsko     print("i16");
318cd74dd17STomasz Miąsko     break;
319cd74dd17STomasz Miąsko   case BasicType::I32:
320cd74dd17STomasz Miąsko     print("i32");
321cd74dd17STomasz Miąsko     break;
322cd74dd17STomasz Miąsko   case BasicType::I64:
323cd74dd17STomasz Miąsko     print("i64");
324cd74dd17STomasz Miąsko     break;
325cd74dd17STomasz Miąsko   case BasicType::I128:
326cd74dd17STomasz Miąsko     print("i128");
327cd74dd17STomasz Miąsko     break;
328cd74dd17STomasz Miąsko   case BasicType::ISize:
329cd74dd17STomasz Miąsko     print("isize");
330cd74dd17STomasz Miąsko     break;
331cd74dd17STomasz Miąsko   case BasicType::U8:
332cd74dd17STomasz Miąsko     print("u8");
333cd74dd17STomasz Miąsko     break;
334cd74dd17STomasz Miąsko   case BasicType::U16:
335cd74dd17STomasz Miąsko     print("u16");
336cd74dd17STomasz Miąsko     break;
337cd74dd17STomasz Miąsko   case BasicType::U32:
338cd74dd17STomasz Miąsko     print("u32");
339cd74dd17STomasz Miąsko     break;
340cd74dd17STomasz Miąsko   case BasicType::U64:
341cd74dd17STomasz Miąsko     print("u64");
342cd74dd17STomasz Miąsko     break;
343cd74dd17STomasz Miąsko   case BasicType::U128:
344cd74dd17STomasz Miąsko     print("u128");
345cd74dd17STomasz Miąsko     break;
346cd74dd17STomasz Miąsko   case BasicType::USize:
347cd74dd17STomasz Miąsko     print("usize");
348cd74dd17STomasz Miąsko     break;
349cd74dd17STomasz Miąsko   case BasicType::F32:
350cd74dd17STomasz Miąsko     print("f32");
351cd74dd17STomasz Miąsko     break;
352cd74dd17STomasz Miąsko   case BasicType::F64:
353cd74dd17STomasz Miąsko     print("f64");
354cd74dd17STomasz Miąsko     break;
355cd74dd17STomasz Miąsko   case BasicType::Str:
356cd74dd17STomasz Miąsko     print("str");
357cd74dd17STomasz Miąsko     break;
358cd74dd17STomasz Miąsko   case BasicType::Placeholder:
359cd74dd17STomasz Miąsko     print("_");
360cd74dd17STomasz Miąsko     break;
361cd74dd17STomasz Miąsko   case BasicType::Unit:
362cd74dd17STomasz Miąsko     print("()");
363cd74dd17STomasz Miąsko     break;
364cd74dd17STomasz Miąsko   case BasicType::Variadic:
365cd74dd17STomasz Miąsko     print("...");
366cd74dd17STomasz Miąsko     break;
367cd74dd17STomasz Miąsko   case BasicType::Never:
368cd74dd17STomasz Miąsko     print("!");
369cd74dd17STomasz Miąsko     break;
370cd74dd17STomasz Miąsko   }
3712961f863STomasz Miąsko }
3722961f863STomasz Miąsko 
3732961f863STomasz Miąsko // <type> = | <basic-type>
3742961f863STomasz Miąsko //          | <path>                      // named type
3752961f863STomasz Miąsko //          | "A" <type> <const>          // [T; N]
3762961f863STomasz Miąsko //          | "S" <type>                  // [T]
3772961f863STomasz Miąsko //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
3782961f863STomasz Miąsko //          | "R" [<lifetime>] <type>     // &T
3792961f863STomasz Miąsko //          | "Q" [<lifetime>] <type>     // &mut T
3802961f863STomasz Miąsko //          | "P" <type>                  // *const T
3812961f863STomasz Miąsko //          | "O" <type>                  // *mut T
3822961f863STomasz Miąsko //          | "F" <fn-sig>                // fn(...) -> ...
3832961f863STomasz Miąsko //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
3842961f863STomasz Miąsko //          | <backref>                   // backref
3852961f863STomasz Miąsko void Demangler::demangleType() {
386cd74dd17STomasz Miąsko   BasicType Type;
387cd74dd17STomasz Miąsko   if (parseBasicType(consume(), Type))
388cd74dd17STomasz Miąsko     printBasicType(Type);
389cd74dd17STomasz Miąsko   else
390cd74dd17STomasz Miąsko     Error = true; // FIXME parse remaining productions.
391cd74dd17STomasz Miąsko }
392cd74dd17STomasz Miąsko 
393cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
394cd74dd17STomasz Miąsko //         | "p"                          // placeholder
395cd74dd17STomasz Miąsko //         | <backref>
396cd74dd17STomasz Miąsko void Demangler::demangleConst() {
397cd74dd17STomasz Miąsko   BasicType Type;
398cd74dd17STomasz Miąsko   if (parseBasicType(consume(), Type)) {
399cd74dd17STomasz Miąsko     switch (Type) {
400cd74dd17STomasz Miąsko     case BasicType::I8:
401cd74dd17STomasz Miąsko     case BasicType::I16:
402cd74dd17STomasz Miąsko     case BasicType::I32:
403cd74dd17STomasz Miąsko     case BasicType::I64:
404cd74dd17STomasz Miąsko     case BasicType::I128:
405cd74dd17STomasz Miąsko     case BasicType::ISize:
406cd74dd17STomasz Miąsko     case BasicType::U8:
407cd74dd17STomasz Miąsko     case BasicType::U16:
408cd74dd17STomasz Miąsko     case BasicType::U32:
409cd74dd17STomasz Miąsko     case BasicType::U64:
410cd74dd17STomasz Miąsko     case BasicType::U128:
411cd74dd17STomasz Miąsko     case BasicType::USize:
412cd74dd17STomasz Miąsko       demangleConstInt();
413cd74dd17STomasz Miąsko       break;
414*fc0f2bb9STomasz Miąsko     case BasicType::Bool:
415*fc0f2bb9STomasz Miąsko       demangleConstBool();
416*fc0f2bb9STomasz Miąsko       break;
417cd74dd17STomasz Miąsko     case BasicType::Placeholder:
418cd74dd17STomasz Miąsko       print('_');
419cd74dd17STomasz Miąsko       break;
420cd74dd17STomasz Miąsko     default:
421*fc0f2bb9STomasz Miąsko       // FIXME demangle backreferences and char constants.
4222961f863STomasz Miąsko       Error = true;
423cd74dd17STomasz Miąsko       break;
424cd74dd17STomasz Miąsko     }
425cd74dd17STomasz Miąsko   } else {
426cd74dd17STomasz Miąsko     Error = true;
427cd74dd17STomasz Miąsko   }
428cd74dd17STomasz Miąsko }
429cd74dd17STomasz Miąsko 
430cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
431cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
432cd74dd17STomasz Miąsko   if (consumeIf('n'))
433cd74dd17STomasz Miąsko     print('-');
434cd74dd17STomasz Miąsko 
435cd74dd17STomasz Miąsko   StringView HexDigits;
436cd74dd17STomasz Miąsko   uint64_t Value = parseHexNumber(HexDigits);
437cd74dd17STomasz Miąsko   if (HexDigits.size() <= 16) {
438cd74dd17STomasz Miąsko     printDecimalNumber(Value);
439cd74dd17STomasz Miąsko   } else {
440cd74dd17STomasz Miąsko     print("0x");
441cd74dd17STomasz Miąsko     print(HexDigits);
4422961f863STomasz Miąsko   }
4432961f863STomasz Miąsko }
4442961f863STomasz Miąsko 
445*fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
446*fc0f2bb9STomasz Miąsko //              | "1_" // true
447*fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
448*fc0f2bb9STomasz Miąsko   StringView HexDigits;
449*fc0f2bb9STomasz Miąsko   parseHexNumber(HexDigits);
450*fc0f2bb9STomasz Miąsko   if (HexDigits == "0")
451*fc0f2bb9STomasz Miąsko     print("false");
452*fc0f2bb9STomasz Miąsko   else if (HexDigits == "1")
453*fc0f2bb9STomasz Miąsko     print("true");
454*fc0f2bb9STomasz Miąsko   else
455*fc0f2bb9STomasz Miąsko     Error = true;
456*fc0f2bb9STomasz Miąsko }
457*fc0f2bb9STomasz Miąsko 
4587310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
4597310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
4607310403eSTomasz Miąsko   bool Punycode = consumeIf('u');
4617310403eSTomasz Miąsko   uint64_t Bytes = parseDecimalNumber();
4627310403eSTomasz Miąsko 
4637310403eSTomasz Miąsko   // Underscore resolves the ambiguity when identifier starts with a decimal
4647310403eSTomasz Miąsko   // digit or another underscore.
4657310403eSTomasz Miąsko   consumeIf('_');
4667310403eSTomasz Miąsko 
4677310403eSTomasz Miąsko   if (Error || Bytes > Input.size() - Position) {
4687310403eSTomasz Miąsko     Error = true;
4697310403eSTomasz Miąsko     return {};
4707310403eSTomasz Miąsko   }
4717310403eSTomasz Miąsko   StringView S = Input.substr(Position, Bytes);
4727310403eSTomasz Miąsko   Position += Bytes;
4737310403eSTomasz Miąsko 
4747310403eSTomasz Miąsko   if (!std::all_of(S.begin(), S.end(), isValid)) {
4757310403eSTomasz Miąsko     Error = true;
4767310403eSTomasz Miąsko     return {};
4777310403eSTomasz Miąsko   }
4787310403eSTomasz Miąsko 
4797310403eSTomasz Miąsko   return {S, Punycode};
4807310403eSTomasz Miąsko }
4817310403eSTomasz Miąsko 
4827310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
48378e94915STomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise.
48478e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
48578e94915STomasz Miąsko   if (!consumeIf(Tag))
48678e94915STomasz Miąsko     return 0;
48778e94915STomasz Miąsko 
48878e94915STomasz Miąsko   uint64_t N = parseBase62Number();
48978e94915STomasz Miąsko   if (Error || !addAssign(N, 1))
49078e94915STomasz Miąsko     return 0;
49178e94915STomasz Miąsko 
49278e94915STomasz Miąsko   return N;
4937310403eSTomasz Miąsko }
4947310403eSTomasz Miąsko 
4957310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
4967310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
4977310403eSTomasz Miąsko // "1_" encodes 2, etc.
4987310403eSTomasz Miąsko //
4997310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
5007310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
5017310403eSTomasz Miąsko   if (consumeIf('_'))
5027310403eSTomasz Miąsko     return 0;
5037310403eSTomasz Miąsko 
5047310403eSTomasz Miąsko   uint64_t Value = 0;
5057310403eSTomasz Miąsko 
5067310403eSTomasz Miąsko   while (true) {
5077310403eSTomasz Miąsko     uint64_t Digit;
5087310403eSTomasz Miąsko     char C = consume();
5097310403eSTomasz Miąsko 
5107310403eSTomasz Miąsko     if (C == '_') {
5117310403eSTomasz Miąsko       break;
5127310403eSTomasz Miąsko     } else if (isDigit(C)) {
5137310403eSTomasz Miąsko       Digit = C - '0';
5147310403eSTomasz Miąsko     } else if (isLower(C)) {
5157310403eSTomasz Miąsko       Digit = 10 + (C - 'a');
5167310403eSTomasz Miąsko     } else if (isUpper(C)) {
5177310403eSTomasz Miąsko       Digit = 10 + 26 + (C - 'A');
5187310403eSTomasz Miąsko     } else {
5197310403eSTomasz Miąsko       Error = true;
5207310403eSTomasz Miąsko       return 0;
5217310403eSTomasz Miąsko     }
5227310403eSTomasz Miąsko 
5237310403eSTomasz Miąsko     if (!mulAssign(Value, 62))
5247310403eSTomasz Miąsko       return 0;
5257310403eSTomasz Miąsko 
5267310403eSTomasz Miąsko     if (!addAssign(Value, Digit))
5277310403eSTomasz Miąsko       return 0;
5287310403eSTomasz Miąsko   }
5297310403eSTomasz Miąsko 
5307310403eSTomasz Miąsko   if (!addAssign(Value, 1))
5317310403eSTomasz Miąsko     return 0;
5327310403eSTomasz Miąsko 
5337310403eSTomasz Miąsko   return Value;
5347310403eSTomasz Miąsko }
5357310403eSTomasz Miąsko 
5367310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
5377310403eSTomasz Miąsko //
5387310403eSTomasz Miąsko // <decimal-number> = "0"
5397310403eSTomasz Miąsko //                  | <1-9> {<0-9>}
5407310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
5417310403eSTomasz Miąsko   char C = look();
5427310403eSTomasz Miąsko   if (!isDigit(C)) {
5437310403eSTomasz Miąsko     Error = true;
5447310403eSTomasz Miąsko     return 0;
5457310403eSTomasz Miąsko   }
5467310403eSTomasz Miąsko 
5477310403eSTomasz Miąsko   if (C == '0') {
5487310403eSTomasz Miąsko     consume();
5497310403eSTomasz Miąsko     return 0;
5507310403eSTomasz Miąsko   }
5517310403eSTomasz Miąsko 
5527310403eSTomasz Miąsko   uint64_t Value = 0;
5537310403eSTomasz Miąsko 
5547310403eSTomasz Miąsko   while (isDigit(look())) {
5557310403eSTomasz Miąsko     if (!mulAssign(Value, 10)) {
5567310403eSTomasz Miąsko       Error = true;
5577310403eSTomasz Miąsko       return 0;
5587310403eSTomasz Miąsko     }
5597310403eSTomasz Miąsko 
5607310403eSTomasz Miąsko     uint64_t D = consume() - '0';
5617310403eSTomasz Miąsko     if (!addAssign(Value, D))
5627310403eSTomasz Miąsko       return 0;
5637310403eSTomasz Miąsko   }
5647310403eSTomasz Miąsko 
5657310403eSTomasz Miąsko   return Value;
5667310403eSTomasz Miąsko }
567cd74dd17STomasz Miąsko 
568cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
569cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
570cd74dd17STomasz Miąsko // HexDigits.size() > 16.
571cd74dd17STomasz Miąsko //
572cd74dd17STomasz Miąsko // <hex-number> = "0_"
573cd74dd17STomasz Miąsko //              | <1-9a-f> {<0-9a-f>} "_"
574cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
575cd74dd17STomasz Miąsko   size_t Start = Position;
576cd74dd17STomasz Miąsko   uint64_t Value = 0;
577cd74dd17STomasz Miąsko 
578cd74dd17STomasz Miąsko   if (!isHexDigit(look()))
579cd74dd17STomasz Miąsko     Error = true;
580cd74dd17STomasz Miąsko 
581cd74dd17STomasz Miąsko   if (consumeIf('0')) {
582cd74dd17STomasz Miąsko     if (!consumeIf('_'))
583cd74dd17STomasz Miąsko       Error = true;
584cd74dd17STomasz Miąsko   } else {
585cd74dd17STomasz Miąsko     while (!Error && !consumeIf('_')) {
586cd74dd17STomasz Miąsko       char C = consume();
587cd74dd17STomasz Miąsko       Value *= 16;
588cd74dd17STomasz Miąsko       if (isDigit(C))
589cd74dd17STomasz Miąsko         Value += C - '0';
590cd74dd17STomasz Miąsko       else if ('a' <= C && C <= 'f')
591cd74dd17STomasz Miąsko         Value += 10 + (C - 'a');
592cd74dd17STomasz Miąsko       else
593cd74dd17STomasz Miąsko         Error = true;
594cd74dd17STomasz Miąsko     }
595cd74dd17STomasz Miąsko   }
596cd74dd17STomasz Miąsko 
597cd74dd17STomasz Miąsko   if (Error) {
598cd74dd17STomasz Miąsko     HexDigits = StringView();
599cd74dd17STomasz Miąsko     return 0;
600cd74dd17STomasz Miąsko   }
601cd74dd17STomasz Miąsko 
602cd74dd17STomasz Miąsko   size_t End = Position - 1;
603cd74dd17STomasz Miąsko   assert(Start < End);
604cd74dd17STomasz Miąsko   HexDigits = Input.substr(Start, End - Start);
605cd74dd17STomasz Miąsko   return Value;
606cd74dd17STomasz Miąsko }
607