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