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;
1067310403eSTomasz Miąsko 
1077310403eSTomasz Miąsko   if (!Mangled.consumeFront("_R")) {
1087310403eSTomasz Miąsko     Error = true;
1097310403eSTomasz Miąsko     return false;
1107310403eSTomasz Miąsko   }
1117310403eSTomasz Miąsko   Input = Mangled;
1127310403eSTomasz Miąsko 
1137310403eSTomasz Miąsko   demanglePath();
1147310403eSTomasz Miąsko 
1157310403eSTomasz Miąsko   // FIXME parse optional <instantiating-crate>.
1167310403eSTomasz Miąsko 
1177310403eSTomasz Miąsko   if (Position != Input.size())
1187310403eSTomasz Miąsko     Error = true;
1197310403eSTomasz Miąsko 
1207310403eSTomasz Miąsko   return !Error;
1217310403eSTomasz Miąsko }
1227310403eSTomasz Miąsko 
1237310403eSTomasz Miąsko // <path> = "C" <identifier>               // crate root
1247310403eSTomasz Miąsko //        | "M" <impl-path> <type>         // <T> (inherent impl)
1257310403eSTomasz Miąsko //        | "X" <impl-path> <type> <path>  // <T as Trait> (trait impl)
1267310403eSTomasz Miąsko //        | "Y" <type> <path>              // <T as Trait> (trait definition)
1277310403eSTomasz Miąsko //        | "N" <ns> <path> <identifier>   // ...::ident (nested path)
1287310403eSTomasz Miąsko //        | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
1297310403eSTomasz Miąsko //        | <backref>
1307310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
1317310403eSTomasz Miąsko // <ns> = "C"      // closure
1327310403eSTomasz Miąsko //      | "S"      // shim
1337310403eSTomasz Miąsko //      | <A-Z>    // other special namespaces
1347310403eSTomasz Miąsko //      | <a-z>    // internal namespaces
1357310403eSTomasz Miąsko void Demangler::demanglePath() {
1367310403eSTomasz Miąsko   if (Error || RecursionLevel >= MaxRecursionLevel) {
1377310403eSTomasz Miąsko     Error = true;
1387310403eSTomasz Miąsko     return;
1397310403eSTomasz Miąsko   }
14078e94915STomasz Miąsko   SwapAndRestore<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
1417310403eSTomasz Miąsko 
1427310403eSTomasz Miąsko   switch (consume()) {
1437310403eSTomasz Miąsko   case 'C': {
1447310403eSTomasz Miąsko     parseOptionalBase62Number('s');
1457310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1467310403eSTomasz Miąsko     print(Ident.Name);
1477310403eSTomasz Miąsko     break;
1487310403eSTomasz Miąsko   }
149f0f2a8b2STomasz Miąsko   case 'M': {
150f0f2a8b2STomasz Miąsko     demangleImplPath();
151f0f2a8b2STomasz Miąsko     print("<");
152f0f2a8b2STomasz Miąsko     demangleType();
153f0f2a8b2STomasz Miąsko     print(">");
154f0f2a8b2STomasz Miąsko     break;
155f0f2a8b2STomasz Miąsko   }
1569fa13800STomasz Miąsko   case 'X': {
1579fa13800STomasz Miąsko     demangleImplPath();
1589fa13800STomasz Miąsko     print("<");
1599fa13800STomasz Miąsko     demangleType();
1609fa13800STomasz Miąsko     print(" as ");
1619fa13800STomasz Miąsko     demanglePath();
1629fa13800STomasz Miąsko     print(">");
1639fa13800STomasz Miąsko     break;
1649fa13800STomasz Miąsko   }
165*f933f7fbSTomasz Miąsko   case 'Y': {
166*f933f7fbSTomasz Miąsko     print("<");
167*f933f7fbSTomasz Miąsko     demangleType();
168*f933f7fbSTomasz Miąsko     print(" as ");
169*f933f7fbSTomasz Miąsko     demanglePath();
170*f933f7fbSTomasz Miąsko     print(">");
171*f933f7fbSTomasz Miąsko     break;
172*f933f7fbSTomasz Miąsko   }
1737310403eSTomasz Miąsko   case 'N': {
1747310403eSTomasz Miąsko     char NS = consume();
1757310403eSTomasz Miąsko     if (!isLower(NS) && !isUpper(NS)) {
1767310403eSTomasz Miąsko       Error = true;
1777310403eSTomasz Miąsko       break;
1787310403eSTomasz Miąsko     }
1797310403eSTomasz Miąsko     demanglePath();
1807310403eSTomasz Miąsko 
18178e94915STomasz Miąsko     uint64_t Disambiguator = parseOptionalBase62Number('s');
1827310403eSTomasz Miąsko     Identifier Ident = parseIdentifier();
1837310403eSTomasz Miąsko 
18478e94915STomasz Miąsko     if (isUpper(NS)) {
18578e94915STomasz Miąsko       // Special namespaces
18678e94915STomasz Miąsko       print("::{");
18778e94915STomasz Miąsko       if (NS == 'C')
18878e94915STomasz Miąsko         print("closure");
18978e94915STomasz Miąsko       else if (NS == 'S')
19078e94915STomasz Miąsko         print("shim");
19178e94915STomasz Miąsko       else
19278e94915STomasz Miąsko         print(NS);
1937310403eSTomasz Miąsko       if (!Ident.empty()) {
19478e94915STomasz Miąsko         print(":");
19578e94915STomasz Miąsko         print(Ident.Name);
19678e94915STomasz Miąsko       }
19778e94915STomasz Miąsko       print('#');
19878e94915STomasz Miąsko       printDecimalNumber(Disambiguator);
19978e94915STomasz Miąsko       print('}');
20078e94915STomasz Miąsko     } else {
20178e94915STomasz Miąsko       // Implementation internal namespaces.
20278e94915STomasz Miąsko       if (!Ident.empty()) {
2037310403eSTomasz Miąsko         print("::");
2047310403eSTomasz Miąsko         print(Ident.Name);
2057310403eSTomasz Miąsko       }
20678e94915STomasz Miąsko     }
2077310403eSTomasz Miąsko     break;
2087310403eSTomasz Miąsko   }
2092961f863STomasz Miąsko   case 'I': {
2102961f863STomasz Miąsko     demanglePath();
2112961f863STomasz Miąsko     print("::<");
2122961f863STomasz Miąsko     for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
2132961f863STomasz Miąsko       if (I > 0)
2142961f863STomasz Miąsko         print(", ");
2152961f863STomasz Miąsko       demangleGenericArg();
2162961f863STomasz Miąsko     }
2172961f863STomasz Miąsko     print(">");
2182961f863STomasz Miąsko     break;
2192961f863STomasz Miąsko   }
2207310403eSTomasz Miąsko   default:
2217310403eSTomasz Miąsko     // FIXME parse remaining productions.
2227310403eSTomasz Miąsko     Error = true;
2237310403eSTomasz Miąsko     break;
2247310403eSTomasz Miąsko   }
2257310403eSTomasz Miąsko }
2267310403eSTomasz Miąsko 
227f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path>
228f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number>
229f0f2a8b2STomasz Miąsko void Demangler::demangleImplPath() {
230f0f2a8b2STomasz Miąsko   SwapAndRestore<bool> SavePrint(Print, false);
231f0f2a8b2STomasz Miąsko   parseOptionalBase62Number('s');
232f0f2a8b2STomasz Miąsko   demanglePath();
233f0f2a8b2STomasz Miąsko }
234f0f2a8b2STomasz Miąsko 
2352961f863STomasz Miąsko // <generic-arg> = <lifetime>
2362961f863STomasz Miąsko //               | <type>
2372961f863STomasz Miąsko //               | "K" <const>
2382961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
2392961f863STomasz Miąsko void Demangler::demangleGenericArg() {
240cd74dd17STomasz Miąsko   if (consumeIf('K'))
241cd74dd17STomasz Miąsko     demangleConst();
242cd74dd17STomasz Miąsko   else
2432961f863STomasz Miąsko     demangleType();
244cd74dd17STomasz Miąsko   // FIXME demangle lifetimes.
2452961f863STomasz Miąsko }
2462961f863STomasz Miąsko 
2472961f863STomasz Miąsko // <basic-type> = "a"      // i8
2482961f863STomasz Miąsko //              | "b"      // bool
2492961f863STomasz Miąsko //              | "c"      // char
2502961f863STomasz Miąsko //              | "d"      // f64
2512961f863STomasz Miąsko //              | "e"      // str
2522961f863STomasz Miąsko //              | "f"      // f32
2532961f863STomasz Miąsko //              | "h"      // u8
2542961f863STomasz Miąsko //              | "i"      // isize
2552961f863STomasz Miąsko //              | "j"      // usize
2562961f863STomasz Miąsko //              | "l"      // i32
2572961f863STomasz Miąsko //              | "m"      // u32
2582961f863STomasz Miąsko //              | "n"      // i128
2592961f863STomasz Miąsko //              | "o"      // u128
2602961f863STomasz Miąsko //              | "s"      // i16
2612961f863STomasz Miąsko //              | "t"      // u16
2622961f863STomasz Miąsko //              | "u"      // ()
2632961f863STomasz Miąsko //              | "v"      // ...
2642961f863STomasz Miąsko //              | "x"      // i64
2652961f863STomasz Miąsko //              | "y"      // u64
2662961f863STomasz Miąsko //              | "z"      // !
2672961f863STomasz Miąsko //              | "p"      // placeholder (e.g. for generic params), shown as _
268cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
269cd74dd17STomasz Miąsko   switch (C) {
270cd74dd17STomasz Miąsko   case 'a':
271cd74dd17STomasz Miąsko     Type = BasicType::I8;
272cd74dd17STomasz Miąsko     return true;
273cd74dd17STomasz Miąsko   case 'b':
274cd74dd17STomasz Miąsko     Type = BasicType::Bool;
275cd74dd17STomasz Miąsko     return true;
276cd74dd17STomasz Miąsko   case 'c':
277cd74dd17STomasz Miąsko     Type = BasicType::Char;
278cd74dd17STomasz Miąsko     return true;
279cd74dd17STomasz Miąsko   case 'd':
280cd74dd17STomasz Miąsko     Type = BasicType::F64;
281cd74dd17STomasz Miąsko     return true;
282cd74dd17STomasz Miąsko   case 'e':
283cd74dd17STomasz Miąsko     Type = BasicType::Str;
284cd74dd17STomasz Miąsko     return true;
285cd74dd17STomasz Miąsko   case 'f':
286cd74dd17STomasz Miąsko     Type = BasicType::F32;
287cd74dd17STomasz Miąsko     return true;
288cd74dd17STomasz Miąsko   case 'h':
289cd74dd17STomasz Miąsko     Type = BasicType::U8;
290cd74dd17STomasz Miąsko     return true;
291cd74dd17STomasz Miąsko   case 'i':
292cd74dd17STomasz Miąsko     Type = BasicType::ISize;
293cd74dd17STomasz Miąsko     return true;
294cd74dd17STomasz Miąsko   case 'j':
295cd74dd17STomasz Miąsko     Type = BasicType::USize;
296cd74dd17STomasz Miąsko     return true;
297cd74dd17STomasz Miąsko   case 'l':
298cd74dd17STomasz Miąsko     Type = BasicType::I32;
299cd74dd17STomasz Miąsko     return true;
300cd74dd17STomasz Miąsko   case 'm':
301cd74dd17STomasz Miąsko     Type = BasicType::U32;
302cd74dd17STomasz Miąsko     return true;
303cd74dd17STomasz Miąsko   case 'n':
304cd74dd17STomasz Miąsko     Type = BasicType::I128;
305cd74dd17STomasz Miąsko     return true;
306cd74dd17STomasz Miąsko   case 'o':
307cd74dd17STomasz Miąsko     Type = BasicType::U128;
308cd74dd17STomasz Miąsko     return true;
309cd74dd17STomasz Miąsko   case 'p':
310cd74dd17STomasz Miąsko     Type = BasicType::Placeholder;
311cd74dd17STomasz Miąsko     return true;
312cd74dd17STomasz Miąsko   case 's':
313cd74dd17STomasz Miąsko     Type = BasicType::I16;
314cd74dd17STomasz Miąsko     return true;
315cd74dd17STomasz Miąsko   case 't':
316cd74dd17STomasz Miąsko     Type = BasicType::U16;
317cd74dd17STomasz Miąsko     return true;
318cd74dd17STomasz Miąsko   case 'u':
319cd74dd17STomasz Miąsko     Type = BasicType::Unit;
320cd74dd17STomasz Miąsko     return true;
321cd74dd17STomasz Miąsko   case 'v':
322cd74dd17STomasz Miąsko     Type = BasicType::Variadic;
323cd74dd17STomasz Miąsko     return true;
324cd74dd17STomasz Miąsko   case 'x':
325cd74dd17STomasz Miąsko     Type = BasicType::I64;
326cd74dd17STomasz Miąsko     return true;
327cd74dd17STomasz Miąsko   case 'y':
328cd74dd17STomasz Miąsko     Type = BasicType::U64;
329cd74dd17STomasz Miąsko     return true;
330cd74dd17STomasz Miąsko   case 'z':
331cd74dd17STomasz Miąsko     Type = BasicType::Never;
332cd74dd17STomasz Miąsko     return true;
333cd74dd17STomasz Miąsko   default:
334cd74dd17STomasz Miąsko     return false;
335cd74dd17STomasz Miąsko   }
336cd74dd17STomasz Miąsko }
337cd74dd17STomasz Miąsko 
338cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
339cd74dd17STomasz Miąsko   switch (Type) {
340cd74dd17STomasz Miąsko   case BasicType::Bool:
341cd74dd17STomasz Miąsko     print("bool");
342cd74dd17STomasz Miąsko     break;
343cd74dd17STomasz Miąsko   case BasicType::Char:
344cd74dd17STomasz Miąsko     print("char");
345cd74dd17STomasz Miąsko     break;
346cd74dd17STomasz Miąsko   case BasicType::I8:
347cd74dd17STomasz Miąsko     print("i8");
348cd74dd17STomasz Miąsko     break;
349cd74dd17STomasz Miąsko   case BasicType::I16:
350cd74dd17STomasz Miąsko     print("i16");
351cd74dd17STomasz Miąsko     break;
352cd74dd17STomasz Miąsko   case BasicType::I32:
353cd74dd17STomasz Miąsko     print("i32");
354cd74dd17STomasz Miąsko     break;
355cd74dd17STomasz Miąsko   case BasicType::I64:
356cd74dd17STomasz Miąsko     print("i64");
357cd74dd17STomasz Miąsko     break;
358cd74dd17STomasz Miąsko   case BasicType::I128:
359cd74dd17STomasz Miąsko     print("i128");
360cd74dd17STomasz Miąsko     break;
361cd74dd17STomasz Miąsko   case BasicType::ISize:
362cd74dd17STomasz Miąsko     print("isize");
363cd74dd17STomasz Miąsko     break;
364cd74dd17STomasz Miąsko   case BasicType::U8:
365cd74dd17STomasz Miąsko     print("u8");
366cd74dd17STomasz Miąsko     break;
367cd74dd17STomasz Miąsko   case BasicType::U16:
368cd74dd17STomasz Miąsko     print("u16");
369cd74dd17STomasz Miąsko     break;
370cd74dd17STomasz Miąsko   case BasicType::U32:
371cd74dd17STomasz Miąsko     print("u32");
372cd74dd17STomasz Miąsko     break;
373cd74dd17STomasz Miąsko   case BasicType::U64:
374cd74dd17STomasz Miąsko     print("u64");
375cd74dd17STomasz Miąsko     break;
376cd74dd17STomasz Miąsko   case BasicType::U128:
377cd74dd17STomasz Miąsko     print("u128");
378cd74dd17STomasz Miąsko     break;
379cd74dd17STomasz Miąsko   case BasicType::USize:
380cd74dd17STomasz Miąsko     print("usize");
381cd74dd17STomasz Miąsko     break;
382cd74dd17STomasz Miąsko   case BasicType::F32:
383cd74dd17STomasz Miąsko     print("f32");
384cd74dd17STomasz Miąsko     break;
385cd74dd17STomasz Miąsko   case BasicType::F64:
386cd74dd17STomasz Miąsko     print("f64");
387cd74dd17STomasz Miąsko     break;
388cd74dd17STomasz Miąsko   case BasicType::Str:
389cd74dd17STomasz Miąsko     print("str");
390cd74dd17STomasz Miąsko     break;
391cd74dd17STomasz Miąsko   case BasicType::Placeholder:
392cd74dd17STomasz Miąsko     print("_");
393cd74dd17STomasz Miąsko     break;
394cd74dd17STomasz Miąsko   case BasicType::Unit:
395cd74dd17STomasz Miąsko     print("()");
396cd74dd17STomasz Miąsko     break;
397cd74dd17STomasz Miąsko   case BasicType::Variadic:
398cd74dd17STomasz Miąsko     print("...");
399cd74dd17STomasz Miąsko     break;
400cd74dd17STomasz Miąsko   case BasicType::Never:
401cd74dd17STomasz Miąsko     print("!");
402cd74dd17STomasz Miąsko     break;
403cd74dd17STomasz Miąsko   }
4042961f863STomasz Miąsko }
4052961f863STomasz Miąsko 
4062961f863STomasz Miąsko // <type> = | <basic-type>
4072961f863STomasz Miąsko //          | <path>                      // named type
4082961f863STomasz Miąsko //          | "A" <type> <const>          // [T; N]
4092961f863STomasz Miąsko //          | "S" <type>                  // [T]
4102961f863STomasz Miąsko //          | "T" {<type>} "E"            // (T1, T2, T3, ...)
4112961f863STomasz Miąsko //          | "R" [<lifetime>] <type>     // &T
4122961f863STomasz Miąsko //          | "Q" [<lifetime>] <type>     // &mut T
4132961f863STomasz Miąsko //          | "P" <type>                  // *const T
4142961f863STomasz Miąsko //          | "O" <type>                  // *mut T
4152961f863STomasz Miąsko //          | "F" <fn-sig>                // fn(...) -> ...
4162961f863STomasz Miąsko //          | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
4172961f863STomasz Miąsko //          | <backref>                   // backref
4182961f863STomasz Miąsko void Demangler::demangleType() {
419cd74dd17STomasz Miąsko   BasicType Type;
420cd74dd17STomasz Miąsko   if (parseBasicType(consume(), Type))
421cd74dd17STomasz Miąsko     printBasicType(Type);
422cd74dd17STomasz Miąsko   else
423cd74dd17STomasz Miąsko     Error = true; // FIXME parse remaining productions.
424cd74dd17STomasz Miąsko }
425cd74dd17STomasz Miąsko 
426cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
427cd74dd17STomasz Miąsko //         | "p"                          // placeholder
428cd74dd17STomasz Miąsko //         | <backref>
429cd74dd17STomasz Miąsko void Demangler::demangleConst() {
430cd74dd17STomasz Miąsko   BasicType Type;
431cd74dd17STomasz Miąsko   if (parseBasicType(consume(), Type)) {
432cd74dd17STomasz Miąsko     switch (Type) {
433cd74dd17STomasz Miąsko     case BasicType::I8:
434cd74dd17STomasz Miąsko     case BasicType::I16:
435cd74dd17STomasz Miąsko     case BasicType::I32:
436cd74dd17STomasz Miąsko     case BasicType::I64:
437cd74dd17STomasz Miąsko     case BasicType::I128:
438cd74dd17STomasz Miąsko     case BasicType::ISize:
439cd74dd17STomasz Miąsko     case BasicType::U8:
440cd74dd17STomasz Miąsko     case BasicType::U16:
441cd74dd17STomasz Miąsko     case BasicType::U32:
442cd74dd17STomasz Miąsko     case BasicType::U64:
443cd74dd17STomasz Miąsko     case BasicType::U128:
444cd74dd17STomasz Miąsko     case BasicType::USize:
445cd74dd17STomasz Miąsko       demangleConstInt();
446cd74dd17STomasz Miąsko       break;
447fc0f2bb9STomasz Miąsko     case BasicType::Bool:
448fc0f2bb9STomasz Miąsko       demangleConstBool();
449fc0f2bb9STomasz Miąsko       break;
4502ba49f6aSTomasz Miąsko     case BasicType::Char:
4512ba49f6aSTomasz Miąsko       demangleConstChar();
4522ba49f6aSTomasz Miąsko       break;
453cd74dd17STomasz Miąsko     case BasicType::Placeholder:
454cd74dd17STomasz Miąsko       print('_');
455cd74dd17STomasz Miąsko       break;
456cd74dd17STomasz Miąsko     default:
4572ba49f6aSTomasz Miąsko       // FIXME demangle backreferences.
4582961f863STomasz Miąsko       Error = true;
459cd74dd17STomasz Miąsko       break;
460cd74dd17STomasz Miąsko     }
461cd74dd17STomasz Miąsko   } else {
462cd74dd17STomasz Miąsko     Error = true;
463cd74dd17STomasz Miąsko   }
464cd74dd17STomasz Miąsko }
465cd74dd17STomasz Miąsko 
466cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
467cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
468cd74dd17STomasz Miąsko   if (consumeIf('n'))
469cd74dd17STomasz Miąsko     print('-');
470cd74dd17STomasz Miąsko 
471cd74dd17STomasz Miąsko   StringView HexDigits;
472cd74dd17STomasz Miąsko   uint64_t Value = parseHexNumber(HexDigits);
473cd74dd17STomasz Miąsko   if (HexDigits.size() <= 16) {
474cd74dd17STomasz Miąsko     printDecimalNumber(Value);
475cd74dd17STomasz Miąsko   } else {
476cd74dd17STomasz Miąsko     print("0x");
477cd74dd17STomasz Miąsko     print(HexDigits);
4782961f863STomasz Miąsko   }
4792961f863STomasz Miąsko }
4802961f863STomasz Miąsko 
481fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
482fc0f2bb9STomasz Miąsko //              | "1_" // true
483fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
484fc0f2bb9STomasz Miąsko   StringView HexDigits;
485fc0f2bb9STomasz Miąsko   parseHexNumber(HexDigits);
486fc0f2bb9STomasz Miąsko   if (HexDigits == "0")
487fc0f2bb9STomasz Miąsko     print("false");
488fc0f2bb9STomasz Miąsko   else if (HexDigits == "1")
489fc0f2bb9STomasz Miąsko     print("true");
490fc0f2bb9STomasz Miąsko   else
491fc0f2bb9STomasz Miąsko     Error = true;
492fc0f2bb9STomasz Miąsko }
493fc0f2bb9STomasz Miąsko 
4942ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character.
4952ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) {
4962ba49f6aSTomasz Miąsko   return 0x20 <= CodePoint && CodePoint <= 0x7e;
4972ba49f6aSTomasz Miąsko }
4982ba49f6aSTomasz Miąsko 
4992ba49f6aSTomasz Miąsko // <const-data> = <hex-number>
5002ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() {
5012ba49f6aSTomasz Miąsko   StringView HexDigits;
5022ba49f6aSTomasz Miąsko   uint64_t CodePoint = parseHexNumber(HexDigits);
5032ba49f6aSTomasz Miąsko   if (Error || HexDigits.size() > 6) {
5042ba49f6aSTomasz Miąsko     Error = true;
5052ba49f6aSTomasz Miąsko     return;
5062ba49f6aSTomasz Miąsko   }
5072ba49f6aSTomasz Miąsko 
5082ba49f6aSTomasz Miąsko   print("'");
5092ba49f6aSTomasz Miąsko   switch (CodePoint) {
5102ba49f6aSTomasz Miąsko   case '\t':
5112ba49f6aSTomasz Miąsko     print(R"(\t)");
5122ba49f6aSTomasz Miąsko     break;
5132ba49f6aSTomasz Miąsko   case '\r':
5142ba49f6aSTomasz Miąsko     print(R"(\r)");
5152ba49f6aSTomasz Miąsko     break;
5162ba49f6aSTomasz Miąsko   case '\n':
5172ba49f6aSTomasz Miąsko     print(R"(\n)");
5182ba49f6aSTomasz Miąsko     break;
5192ba49f6aSTomasz Miąsko   case '\\':
5202ba49f6aSTomasz Miąsko     print(R"(\\)");
5212ba49f6aSTomasz Miąsko     break;
5222ba49f6aSTomasz Miąsko   case '"':
5232ba49f6aSTomasz Miąsko     print(R"(")");
5242ba49f6aSTomasz Miąsko     break;
5252ba49f6aSTomasz Miąsko   case '\'':
5262ba49f6aSTomasz Miąsko     print(R"(\')");
5272ba49f6aSTomasz Miąsko     break;
5282ba49f6aSTomasz Miąsko   default:
5292ba49f6aSTomasz Miąsko     if (isAsciiPrintable(CodePoint)) {
5302ba49f6aSTomasz Miąsko       char C = CodePoint;
5312ba49f6aSTomasz Miąsko       print(C);
5322ba49f6aSTomasz Miąsko     } else {
5332ba49f6aSTomasz Miąsko       print(R"(\u{)");
5342ba49f6aSTomasz Miąsko       print(HexDigits);
5352ba49f6aSTomasz Miąsko       print('}');
5362ba49f6aSTomasz Miąsko     }
5372ba49f6aSTomasz Miąsko     break;
5382ba49f6aSTomasz Miąsko   }
5392ba49f6aSTomasz Miąsko   print('\'');
5402ba49f6aSTomasz Miąsko }
5412ba49f6aSTomasz Miąsko 
5427310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
5437310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
5447310403eSTomasz Miąsko   bool Punycode = consumeIf('u');
5457310403eSTomasz Miąsko   uint64_t Bytes = parseDecimalNumber();
5467310403eSTomasz Miąsko 
5477310403eSTomasz Miąsko   // Underscore resolves the ambiguity when identifier starts with a decimal
5487310403eSTomasz Miąsko   // digit or another underscore.
5497310403eSTomasz Miąsko   consumeIf('_');
5507310403eSTomasz Miąsko 
5517310403eSTomasz Miąsko   if (Error || Bytes > Input.size() - Position) {
5527310403eSTomasz Miąsko     Error = true;
5537310403eSTomasz Miąsko     return {};
5547310403eSTomasz Miąsko   }
5557310403eSTomasz Miąsko   StringView S = Input.substr(Position, Bytes);
5567310403eSTomasz Miąsko   Position += Bytes;
5577310403eSTomasz Miąsko 
5587310403eSTomasz Miąsko   if (!std::all_of(S.begin(), S.end(), isValid)) {
5597310403eSTomasz Miąsko     Error = true;
5607310403eSTomasz Miąsko     return {};
5617310403eSTomasz Miąsko   }
5627310403eSTomasz Miąsko 
5637310403eSTomasz Miąsko   return {S, Punycode};
5647310403eSTomasz Miąsko }
5657310403eSTomasz Miąsko 
5667310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
56778e94915STomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise.
56878e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
56978e94915STomasz Miąsko   if (!consumeIf(Tag))
57078e94915STomasz Miąsko     return 0;
57178e94915STomasz Miąsko 
57278e94915STomasz Miąsko   uint64_t N = parseBase62Number();
57378e94915STomasz Miąsko   if (Error || !addAssign(N, 1))
57478e94915STomasz Miąsko     return 0;
57578e94915STomasz Miąsko 
57678e94915STomasz Miąsko   return N;
5777310403eSTomasz Miąsko }
5787310403eSTomasz Miąsko 
5797310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
5807310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
5817310403eSTomasz Miąsko // "1_" encodes 2, etc.
5827310403eSTomasz Miąsko //
5837310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
5847310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
5857310403eSTomasz Miąsko   if (consumeIf('_'))
5867310403eSTomasz Miąsko     return 0;
5877310403eSTomasz Miąsko 
5887310403eSTomasz Miąsko   uint64_t Value = 0;
5897310403eSTomasz Miąsko 
5907310403eSTomasz Miąsko   while (true) {
5917310403eSTomasz Miąsko     uint64_t Digit;
5927310403eSTomasz Miąsko     char C = consume();
5937310403eSTomasz Miąsko 
5947310403eSTomasz Miąsko     if (C == '_') {
5957310403eSTomasz Miąsko       break;
5967310403eSTomasz Miąsko     } else if (isDigit(C)) {
5977310403eSTomasz Miąsko       Digit = C - '0';
5987310403eSTomasz Miąsko     } else if (isLower(C)) {
5997310403eSTomasz Miąsko       Digit = 10 + (C - 'a');
6007310403eSTomasz Miąsko     } else if (isUpper(C)) {
6017310403eSTomasz Miąsko       Digit = 10 + 26 + (C - 'A');
6027310403eSTomasz Miąsko     } else {
6037310403eSTomasz Miąsko       Error = true;
6047310403eSTomasz Miąsko       return 0;
6057310403eSTomasz Miąsko     }
6067310403eSTomasz Miąsko 
6077310403eSTomasz Miąsko     if (!mulAssign(Value, 62))
6087310403eSTomasz Miąsko       return 0;
6097310403eSTomasz Miąsko 
6107310403eSTomasz Miąsko     if (!addAssign(Value, Digit))
6117310403eSTomasz Miąsko       return 0;
6127310403eSTomasz Miąsko   }
6137310403eSTomasz Miąsko 
6147310403eSTomasz Miąsko   if (!addAssign(Value, 1))
6157310403eSTomasz Miąsko     return 0;
6167310403eSTomasz Miąsko 
6177310403eSTomasz Miąsko   return Value;
6187310403eSTomasz Miąsko }
6197310403eSTomasz Miąsko 
6207310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
6217310403eSTomasz Miąsko //
6227310403eSTomasz Miąsko // <decimal-number> = "0"
6237310403eSTomasz Miąsko //                  | <1-9> {<0-9>}
6247310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
6257310403eSTomasz Miąsko   char C = look();
6267310403eSTomasz Miąsko   if (!isDigit(C)) {
6277310403eSTomasz Miąsko     Error = true;
6287310403eSTomasz Miąsko     return 0;
6297310403eSTomasz Miąsko   }
6307310403eSTomasz Miąsko 
6317310403eSTomasz Miąsko   if (C == '0') {
6327310403eSTomasz Miąsko     consume();
6337310403eSTomasz Miąsko     return 0;
6347310403eSTomasz Miąsko   }
6357310403eSTomasz Miąsko 
6367310403eSTomasz Miąsko   uint64_t Value = 0;
6377310403eSTomasz Miąsko 
6387310403eSTomasz Miąsko   while (isDigit(look())) {
6397310403eSTomasz Miąsko     if (!mulAssign(Value, 10)) {
6407310403eSTomasz Miąsko       Error = true;
6417310403eSTomasz Miąsko       return 0;
6427310403eSTomasz Miąsko     }
6437310403eSTomasz Miąsko 
6447310403eSTomasz Miąsko     uint64_t D = consume() - '0';
6457310403eSTomasz Miąsko     if (!addAssign(Value, D))
6467310403eSTomasz Miąsko       return 0;
6477310403eSTomasz Miąsko   }
6487310403eSTomasz Miąsko 
6497310403eSTomasz Miąsko   return Value;
6507310403eSTomasz Miąsko }
651cd74dd17STomasz Miąsko 
652cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
653cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
654cd74dd17STomasz Miąsko // HexDigits.size() > 16.
655cd74dd17STomasz Miąsko //
656cd74dd17STomasz Miąsko // <hex-number> = "0_"
657cd74dd17STomasz Miąsko //              | <1-9a-f> {<0-9a-f>} "_"
658cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
659cd74dd17STomasz Miąsko   size_t Start = Position;
660cd74dd17STomasz Miąsko   uint64_t Value = 0;
661cd74dd17STomasz Miąsko 
662cd74dd17STomasz Miąsko   if (!isHexDigit(look()))
663cd74dd17STomasz Miąsko     Error = true;
664cd74dd17STomasz Miąsko 
665cd74dd17STomasz Miąsko   if (consumeIf('0')) {
666cd74dd17STomasz Miąsko     if (!consumeIf('_'))
667cd74dd17STomasz Miąsko       Error = true;
668cd74dd17STomasz Miąsko   } else {
669cd74dd17STomasz Miąsko     while (!Error && !consumeIf('_')) {
670cd74dd17STomasz Miąsko       char C = consume();
671cd74dd17STomasz Miąsko       Value *= 16;
672cd74dd17STomasz Miąsko       if (isDigit(C))
673cd74dd17STomasz Miąsko         Value += C - '0';
674cd74dd17STomasz Miąsko       else if ('a' <= C && C <= 'f')
675cd74dd17STomasz Miąsko         Value += 10 + (C - 'a');
676cd74dd17STomasz Miąsko       else
677cd74dd17STomasz Miąsko         Error = true;
678cd74dd17STomasz Miąsko     }
679cd74dd17STomasz Miąsko   }
680cd74dd17STomasz Miąsko 
681cd74dd17STomasz Miąsko   if (Error) {
682cd74dd17STomasz Miąsko     HexDigits = StringView();
683cd74dd17STomasz Miąsko     return 0;
684cd74dd17STomasz Miąsko   }
685cd74dd17STomasz Miąsko 
686cd74dd17STomasz Miąsko   size_t End = Position - 1;
687cd74dd17STomasz Miąsko   assert(Start < End);
688cd74dd17STomasz Miąsko   HexDigits = Input.substr(Start, End - Start);
689cd74dd17STomasz Miąsko   return Value;
690cd74dd17STomasz Miąsko }
691