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"
156cc6ada1STomasz Miąsko #include "llvm/Demangle/StringView.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>
237310403eSTomasz Miąsko
247310403eSTomasz Miąsko using namespace llvm;
256cc6ada1STomasz Miąsko
262e97236aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer;
2751f6caf2SNathan Sidwell using llvm::itanium_demangle::ScopedOverride;
286cc6ada1STomasz Miąsko using llvm::itanium_demangle::StringView;
296cc6ada1STomasz Miąsko
306cc6ada1STomasz Miąsko namespace {
316cc6ada1STomasz Miąsko
326cc6ada1STomasz Miąsko struct Identifier {
336cc6ada1STomasz Miąsko StringView Name;
346cc6ada1STomasz Miąsko bool Punycode;
356cc6ada1STomasz Miąsko
empty__anon798090d70111::Identifier366cc6ada1STomasz Miąsko bool empty() const { return Name.empty(); }
376cc6ada1STomasz Miąsko };
386cc6ada1STomasz Miąsko
396cc6ada1STomasz Miąsko enum class BasicType {
406cc6ada1STomasz Miąsko Bool,
416cc6ada1STomasz Miąsko Char,
426cc6ada1STomasz Miąsko I8,
436cc6ada1STomasz Miąsko I16,
446cc6ada1STomasz Miąsko I32,
456cc6ada1STomasz Miąsko I64,
466cc6ada1STomasz Miąsko I128,
476cc6ada1STomasz Miąsko ISize,
486cc6ada1STomasz Miąsko U8,
496cc6ada1STomasz Miąsko U16,
506cc6ada1STomasz Miąsko U32,
516cc6ada1STomasz Miąsko U64,
526cc6ada1STomasz Miąsko U128,
536cc6ada1STomasz Miąsko USize,
546cc6ada1STomasz Miąsko F32,
556cc6ada1STomasz Miąsko F64,
566cc6ada1STomasz Miąsko Str,
576cc6ada1STomasz Miąsko Placeholder,
586cc6ada1STomasz Miąsko Unit,
596cc6ada1STomasz Miąsko Variadic,
606cc6ada1STomasz Miąsko Never,
616cc6ada1STomasz Miąsko };
626cc6ada1STomasz Miąsko
636cc6ada1STomasz Miąsko enum class IsInType {
646cc6ada1STomasz Miąsko No,
656cc6ada1STomasz Miąsko Yes,
666cc6ada1STomasz Miąsko };
676cc6ada1STomasz Miąsko
686cc6ada1STomasz Miąsko enum class LeaveGenericsOpen {
696cc6ada1STomasz Miąsko No,
706cc6ada1STomasz Miąsko Yes,
716cc6ada1STomasz Miąsko };
726cc6ada1STomasz Miąsko
736cc6ada1STomasz Miąsko class Demangler {
746cc6ada1STomasz Miąsko // Maximum recursion level. Used to avoid stack overflow.
756cc6ada1STomasz Miąsko size_t MaxRecursionLevel;
766cc6ada1STomasz Miąsko // Current recursion level.
776cc6ada1STomasz Miąsko size_t RecursionLevel;
786cc6ada1STomasz Miąsko size_t BoundLifetimes;
796cc6ada1STomasz Miąsko // Input string that is being demangled with "_R" prefix removed.
806cc6ada1STomasz Miąsko StringView Input;
816cc6ada1STomasz Miąsko // Position in the input string.
826cc6ada1STomasz Miąsko size_t Position;
836cc6ada1STomasz Miąsko // When true, print methods append the output to the stream.
846cc6ada1STomasz Miąsko // When false, the output is suppressed.
856cc6ada1STomasz Miąsko bool Print;
866cc6ada1STomasz Miąsko // True if an error occurred.
876cc6ada1STomasz Miąsko bool Error;
886cc6ada1STomasz Miąsko
896cc6ada1STomasz Miąsko public:
906cc6ada1STomasz Miąsko // Demangled output.
912e97236aSLuís Ferreira OutputBuffer Output;
926cc6ada1STomasz Miąsko
936cc6ada1STomasz Miąsko Demangler(size_t MaxRecursionLevel = 500);
946cc6ada1STomasz Miąsko
956cc6ada1STomasz Miąsko bool demangle(StringView MangledName);
966cc6ada1STomasz Miąsko
976cc6ada1STomasz Miąsko private:
986cc6ada1STomasz Miąsko bool demanglePath(IsInType Type,
996cc6ada1STomasz Miąsko LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No);
1006cc6ada1STomasz Miąsko void demangleImplPath(IsInType InType);
1016cc6ada1STomasz Miąsko void demangleGenericArg();
1026cc6ada1STomasz Miąsko void demangleType();
1036cc6ada1STomasz Miąsko void demangleFnSig();
1046cc6ada1STomasz Miąsko void demangleDynBounds();
1056cc6ada1STomasz Miąsko void demangleDynTrait();
1066cc6ada1STomasz Miąsko void demangleOptionalBinder();
1076cc6ada1STomasz Miąsko void demangleConst();
1086cc6ada1STomasz Miąsko void demangleConstInt();
1096cc6ada1STomasz Miąsko void demangleConstBool();
1106cc6ada1STomasz Miąsko void demangleConstChar();
1116cc6ada1STomasz Miąsko
demangleBackref(Callable Demangler)1126cc6ada1STomasz Miąsko template <typename Callable> void demangleBackref(Callable Demangler) {
1136cc6ada1STomasz Miąsko uint64_t Backref = parseBase62Number();
1146cc6ada1STomasz Miąsko if (Error || Backref >= Position) {
1156cc6ada1STomasz Miąsko Error = true;
1166cc6ada1STomasz Miąsko return;
1176cc6ada1STomasz Miąsko }
1186cc6ada1STomasz Miąsko
1196cc6ada1STomasz Miąsko if (!Print)
1206cc6ada1STomasz Miąsko return;
1216cc6ada1STomasz Miąsko
12251f6caf2SNathan Sidwell ScopedOverride<size_t> SavePosition(Position, Position);
1236cc6ada1STomasz Miąsko Position = Backref;
1246cc6ada1STomasz Miąsko Demangler();
1256cc6ada1STomasz Miąsko }
1266cc6ada1STomasz Miąsko
1276cc6ada1STomasz Miąsko Identifier parseIdentifier();
1286cc6ada1STomasz Miąsko uint64_t parseOptionalBase62Number(char Tag);
1296cc6ada1STomasz Miąsko uint64_t parseBase62Number();
1306cc6ada1STomasz Miąsko uint64_t parseDecimalNumber();
1316cc6ada1STomasz Miąsko uint64_t parseHexNumber(StringView &HexDigits);
1326cc6ada1STomasz Miąsko
1336cc6ada1STomasz Miąsko void print(char C);
1346cc6ada1STomasz Miąsko void print(StringView S);
1356cc6ada1STomasz Miąsko void printDecimalNumber(uint64_t N);
1366cc6ada1STomasz Miąsko void printBasicType(BasicType);
1376cc6ada1STomasz Miąsko void printLifetime(uint64_t Index);
138c8c2b462STomasz Miąsko void printIdentifier(Identifier Ident);
1396cc6ada1STomasz Miąsko
1406cc6ada1STomasz Miąsko char look() const;
1416cc6ada1STomasz Miąsko char consume();
1426cc6ada1STomasz Miąsko bool consumeIf(char Prefix);
1436cc6ada1STomasz Miąsko
1446cc6ada1STomasz Miąsko bool addAssign(uint64_t &A, uint64_t B);
1456cc6ada1STomasz Miąsko bool mulAssign(uint64_t &A, uint64_t B);
1466cc6ada1STomasz Miąsko };
1476cc6ada1STomasz Miąsko
1486cc6ada1STomasz Miąsko } // namespace
1497310403eSTomasz Miąsko
rustDemangle(const char * MangledName)150201c4b9cSNathan Sidwell char *llvm::rustDemangle(const char *MangledName) {
151201c4b9cSNathan Sidwell if (MangledName == nullptr)
1527310403eSTomasz Miąsko return nullptr;
1537310403eSTomasz Miąsko
1547310403eSTomasz Miąsko // Return early if mangled name doesn't look like a Rust symbol.
1557310403eSTomasz Miąsko StringView Mangled(MangledName);
156201c4b9cSNathan Sidwell if (!Mangled.startsWith("_R"))
1577310403eSTomasz Miąsko return nullptr;
1587310403eSTomasz Miąsko
1597310403eSTomasz Miąsko Demangler D;
160*aabeb5ebSKirill Stoimenov if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024))
161*aabeb5ebSKirill Stoimenov return nullptr;
162*aabeb5ebSKirill Stoimenov
1637310403eSTomasz Miąsko if (!D.demangle(Mangled)) {
1647310403eSTomasz Miąsko std::free(D.Output.getBuffer());
1657310403eSTomasz Miąsko return nullptr;
1667310403eSTomasz Miąsko }
1677310403eSTomasz Miąsko
1687310403eSTomasz Miąsko D.Output += '\0';
1697310403eSTomasz Miąsko
170201c4b9cSNathan Sidwell return D.Output.getBuffer();
1717310403eSTomasz Miąsko }
1727310403eSTomasz Miąsko
Demangler(size_t MaxRecursionLevel)1737310403eSTomasz Miąsko Demangler::Demangler(size_t MaxRecursionLevel)
1747310403eSTomasz Miąsko : MaxRecursionLevel(MaxRecursionLevel) {}
1757310403eSTomasz Miąsko
isDigit(const char C)1767310403eSTomasz Miąsko static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
1777310403eSTomasz Miąsko
isHexDigit(const char C)178cd74dd17STomasz Miąsko static inline bool isHexDigit(const char C) {
179cd74dd17STomasz Miąsko return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
180cd74dd17STomasz Miąsko }
181cd74dd17STomasz Miąsko
isLower(const char C)1827310403eSTomasz Miąsko static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
1837310403eSTomasz Miąsko
isUpper(const char C)1847310403eSTomasz Miąsko static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
1857310403eSTomasz Miąsko
1867310403eSTomasz Miąsko /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
isValid(const char C)1877310403eSTomasz Miąsko static inline bool isValid(const char C) {
1887310403eSTomasz Miąsko return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
1897310403eSTomasz Miąsko }
1907310403eSTomasz Miąsko
1917310403eSTomasz Miąsko // Demangles Rust v0 mangled symbol. Returns true when successful, and false
1927310403eSTomasz Miąsko // otherwise. The demangled symbol is stored in Output field. It is
1937310403eSTomasz Miąsko // responsibility of the caller to free the memory behind the output stream.
1947310403eSTomasz Miąsko //
1957310403eSTomasz Miąsko // <symbol-name> = "_R" <path> [<instantiating-crate>]
demangle(StringView Mangled)1967310403eSTomasz Miąsko bool Demangler::demangle(StringView Mangled) {
1977310403eSTomasz Miąsko Position = 0;
1987310403eSTomasz Miąsko Error = false;
199f0f2a8b2STomasz Miąsko Print = true;
2007310403eSTomasz Miąsko RecursionLevel = 0;
201a67a234eSTomasz Miąsko BoundLifetimes = 0;
2027310403eSTomasz Miąsko
2037310403eSTomasz Miąsko if (!Mangled.consumeFront("_R")) {
2047310403eSTomasz Miąsko Error = true;
2057310403eSTomasz Miąsko return false;
2067310403eSTomasz Miąsko }
2072a5bb9c8STomasz Miąsko size_t Dot = Mangled.find('.');
2082a5bb9c8STomasz Miąsko Input = Mangled.substr(0, Dot);
2092a5bb9c8STomasz Miąsko StringView Suffix = Mangled.dropFront(Dot);
2107310403eSTomasz Miąsko
2116cc6ada1STomasz Miąsko demanglePath(IsInType::No);
2127310403eSTomasz Miąsko
21343929cccSTomasz Miąsko if (Position != Input.size()) {
21451f6caf2SNathan Sidwell ScopedOverride<bool> SavePrint(Print, false);
2156cc6ada1STomasz Miąsko demanglePath(IsInType::No);
21643929cccSTomasz Miąsko }
2177310403eSTomasz Miąsko
2187310403eSTomasz Miąsko if (Position != Input.size())
2197310403eSTomasz Miąsko Error = true;
2207310403eSTomasz Miąsko
2212a5bb9c8STomasz Miąsko if (!Suffix.empty()) {
2222a5bb9c8STomasz Miąsko print(" (");
2232a5bb9c8STomasz Miąsko print(Suffix);
2242a5bb9c8STomasz Miąsko print(")");
2252a5bb9c8STomasz Miąsko }
2262a5bb9c8STomasz Miąsko
2277310403eSTomasz Miąsko return !Error;
2287310403eSTomasz Miąsko }
2297310403eSTomasz Miąsko
230619a65e5STomasz Miąsko // Demangles a path. InType indicates whether a path is inside a type. When
231619a65e5STomasz Miąsko // LeaveOpen is true, a closing `>` after generic arguments is omitted from the
232619a65e5STomasz Miąsko // output. Return value indicates whether generics arguments have been left
233619a65e5STomasz Miąsko // open.
23406833297STomasz Miąsko //
2357310403eSTomasz Miąsko // <path> = "C" <identifier> // crate root
2367310403eSTomasz Miąsko // | "M" <impl-path> <type> // <T> (inherent impl)
2377310403eSTomasz Miąsko // | "X" <impl-path> <type> <path> // <T as Trait> (trait impl)
2387310403eSTomasz Miąsko // | "Y" <type> <path> // <T as Trait> (trait definition)
2397310403eSTomasz Miąsko // | "N" <ns> <path> <identifier> // ...::ident (nested path)
2407310403eSTomasz Miąsko // | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args)
2417310403eSTomasz Miąsko // | <backref>
2427310403eSTomasz Miąsko // <identifier> = [<disambiguator>] <undisambiguated-identifier>
2437310403eSTomasz Miąsko // <ns> = "C" // closure
2447310403eSTomasz Miąsko // | "S" // shim
2457310403eSTomasz Miąsko // | <A-Z> // other special namespaces
2467310403eSTomasz Miąsko // | <a-z> // internal namespaces
demanglePath(IsInType InType,LeaveGenericsOpen LeaveOpen)2476cc6ada1STomasz Miąsko bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) {
2487310403eSTomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) {
2497310403eSTomasz Miąsko Error = true;
250619a65e5STomasz Miąsko return false;
2517310403eSTomasz Miąsko }
25251f6caf2SNathan Sidwell ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
2537310403eSTomasz Miąsko
2547310403eSTomasz Miąsko switch (consume()) {
2557310403eSTomasz Miąsko case 'C': {
2567310403eSTomasz Miąsko parseOptionalBase62Number('s');
257c8c2b462STomasz Miąsko printIdentifier(parseIdentifier());
2587310403eSTomasz Miąsko break;
2597310403eSTomasz Miąsko }
260f0f2a8b2STomasz Miąsko case 'M': {
26106833297STomasz Miąsko demangleImplPath(InType);
262f0f2a8b2STomasz Miąsko print("<");
263f0f2a8b2STomasz Miąsko demangleType();
264f0f2a8b2STomasz Miąsko print(">");
265f0f2a8b2STomasz Miąsko break;
266f0f2a8b2STomasz Miąsko }
2679fa13800STomasz Miąsko case 'X': {
26806833297STomasz Miąsko demangleImplPath(InType);
2699fa13800STomasz Miąsko print("<");
2709fa13800STomasz Miąsko demangleType();
2719fa13800STomasz Miąsko print(" as ");
2726cc6ada1STomasz Miąsko demanglePath(IsInType::Yes);
2739fa13800STomasz Miąsko print(">");
2749fa13800STomasz Miąsko break;
2759fa13800STomasz Miąsko }
276f933f7fbSTomasz Miąsko case 'Y': {
277f933f7fbSTomasz Miąsko print("<");
278f933f7fbSTomasz Miąsko demangleType();
279f933f7fbSTomasz Miąsko print(" as ");
2806cc6ada1STomasz Miąsko demanglePath(IsInType::Yes);
281f933f7fbSTomasz Miąsko print(">");
282f933f7fbSTomasz Miąsko break;
283f933f7fbSTomasz Miąsko }
2847310403eSTomasz Miąsko case 'N': {
2857310403eSTomasz Miąsko char NS = consume();
2867310403eSTomasz Miąsko if (!isLower(NS) && !isUpper(NS)) {
2877310403eSTomasz Miąsko Error = true;
2887310403eSTomasz Miąsko break;
2897310403eSTomasz Miąsko }
29006833297STomasz Miąsko demanglePath(InType);
2917310403eSTomasz Miąsko
29278e94915STomasz Miąsko uint64_t Disambiguator = parseOptionalBase62Number('s');
2937310403eSTomasz Miąsko Identifier Ident = parseIdentifier();
2947310403eSTomasz Miąsko
29578e94915STomasz Miąsko if (isUpper(NS)) {
29678e94915STomasz Miąsko // Special namespaces
29778e94915STomasz Miąsko print("::{");
29878e94915STomasz Miąsko if (NS == 'C')
29978e94915STomasz Miąsko print("closure");
30078e94915STomasz Miąsko else if (NS == 'S')
30178e94915STomasz Miąsko print("shim");
30278e94915STomasz Miąsko else
30378e94915STomasz Miąsko print(NS);
3047310403eSTomasz Miąsko if (!Ident.empty()) {
30578e94915STomasz Miąsko print(":");
306c8c2b462STomasz Miąsko printIdentifier(Ident);
30778e94915STomasz Miąsko }
30878e94915STomasz Miąsko print('#');
30978e94915STomasz Miąsko printDecimalNumber(Disambiguator);
31078e94915STomasz Miąsko print('}');
31178e94915STomasz Miąsko } else {
31278e94915STomasz Miąsko // Implementation internal namespaces.
31378e94915STomasz Miąsko if (!Ident.empty()) {
3147310403eSTomasz Miąsko print("::");
315c8c2b462STomasz Miąsko printIdentifier(Ident);
3167310403eSTomasz Miąsko }
31778e94915STomasz Miąsko }
3187310403eSTomasz Miąsko break;
3197310403eSTomasz Miąsko }
3202961f863STomasz Miąsko case 'I': {
32106833297STomasz Miąsko demanglePath(InType);
32206833297STomasz Miąsko // Omit "::" when in a type, where it is optional.
3236cc6ada1STomasz Miąsko if (InType == IsInType::No)
32406833297STomasz Miąsko print("::");
32506833297STomasz Miąsko print("<");
3262961f863STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
3272961f863STomasz Miąsko if (I > 0)
3282961f863STomasz Miąsko print(", ");
3292961f863STomasz Miąsko demangleGenericArg();
3302961f863STomasz Miąsko }
3316cc6ada1STomasz Miąsko if (LeaveOpen == LeaveGenericsOpen::Yes)
332619a65e5STomasz Miąsko return true;
333619a65e5STomasz Miąsko else
3342961f863STomasz Miąsko print(">");
3352961f863STomasz Miąsko break;
3362961f863STomasz Miąsko }
33782b7e822STomasz Miąsko case 'B': {
33882b7e822STomasz Miąsko bool IsOpen = false;
33982b7e822STomasz Miąsko demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
34082b7e822STomasz Miąsko return IsOpen;
34182b7e822STomasz Miąsko }
3427310403eSTomasz Miąsko default:
3437310403eSTomasz Miąsko Error = true;
3447310403eSTomasz Miąsko break;
3457310403eSTomasz Miąsko }
346619a65e5STomasz Miąsko
347619a65e5STomasz Miąsko return false;
3487310403eSTomasz Miąsko }
3497310403eSTomasz Miąsko
350f0f2a8b2STomasz Miąsko // <impl-path> = [<disambiguator>] <path>
351f0f2a8b2STomasz Miąsko // <disambiguator> = "s" <base-62-number>
demangleImplPath(IsInType InType)3526cc6ada1STomasz Miąsko void Demangler::demangleImplPath(IsInType InType) {
35351f6caf2SNathan Sidwell ScopedOverride<bool> SavePrint(Print, false);
354f0f2a8b2STomasz Miąsko parseOptionalBase62Number('s');
35506833297STomasz Miąsko demanglePath(InType);
356f0f2a8b2STomasz Miąsko }
357f0f2a8b2STomasz Miąsko
3582961f863STomasz Miąsko // <generic-arg> = <lifetime>
3592961f863STomasz Miąsko // | <type>
3602961f863STomasz Miąsko // | "K" <const>
3612961f863STomasz Miąsko // <lifetime> = "L" <base-62-number>
demangleGenericArg()3622961f863STomasz Miąsko void Demangler::demangleGenericArg() {
363a67a234eSTomasz Miąsko if (consumeIf('L'))
364a67a234eSTomasz Miąsko printLifetime(parseBase62Number());
365a67a234eSTomasz Miąsko else if (consumeIf('K'))
366cd74dd17STomasz Miąsko demangleConst();
367cd74dd17STomasz Miąsko else
3682961f863STomasz Miąsko demangleType();
3692961f863STomasz Miąsko }
3702961f863STomasz Miąsko
3712961f863STomasz Miąsko // <basic-type> = "a" // i8
3722961f863STomasz Miąsko // | "b" // bool
3732961f863STomasz Miąsko // | "c" // char
3742961f863STomasz Miąsko // | "d" // f64
3752961f863STomasz Miąsko // | "e" // str
3762961f863STomasz Miąsko // | "f" // f32
3772961f863STomasz Miąsko // | "h" // u8
3782961f863STomasz Miąsko // | "i" // isize
3792961f863STomasz Miąsko // | "j" // usize
3802961f863STomasz Miąsko // | "l" // i32
3812961f863STomasz Miąsko // | "m" // u32
3822961f863STomasz Miąsko // | "n" // i128
3832961f863STomasz Miąsko // | "o" // u128
3842961f863STomasz Miąsko // | "s" // i16
3852961f863STomasz Miąsko // | "t" // u16
3862961f863STomasz Miąsko // | "u" // ()
3872961f863STomasz Miąsko // | "v" // ...
3882961f863STomasz Miąsko // | "x" // i64
3892961f863STomasz Miąsko // | "y" // u64
3902961f863STomasz Miąsko // | "z" // !
3912961f863STomasz Miąsko // | "p" // placeholder (e.g. for generic params), shown as _
parseBasicType(char C,BasicType & Type)392cd74dd17STomasz Miąsko static bool parseBasicType(char C, BasicType &Type) {
393cd74dd17STomasz Miąsko switch (C) {
394cd74dd17STomasz Miąsko case 'a':
395cd74dd17STomasz Miąsko Type = BasicType::I8;
396cd74dd17STomasz Miąsko return true;
397cd74dd17STomasz Miąsko case 'b':
398cd74dd17STomasz Miąsko Type = BasicType::Bool;
399cd74dd17STomasz Miąsko return true;
400cd74dd17STomasz Miąsko case 'c':
401cd74dd17STomasz Miąsko Type = BasicType::Char;
402cd74dd17STomasz Miąsko return true;
403cd74dd17STomasz Miąsko case 'd':
404cd74dd17STomasz Miąsko Type = BasicType::F64;
405cd74dd17STomasz Miąsko return true;
406cd74dd17STomasz Miąsko case 'e':
407cd74dd17STomasz Miąsko Type = BasicType::Str;
408cd74dd17STomasz Miąsko return true;
409cd74dd17STomasz Miąsko case 'f':
410cd74dd17STomasz Miąsko Type = BasicType::F32;
411cd74dd17STomasz Miąsko return true;
412cd74dd17STomasz Miąsko case 'h':
413cd74dd17STomasz Miąsko Type = BasicType::U8;
414cd74dd17STomasz Miąsko return true;
415cd74dd17STomasz Miąsko case 'i':
416cd74dd17STomasz Miąsko Type = BasicType::ISize;
417cd74dd17STomasz Miąsko return true;
418cd74dd17STomasz Miąsko case 'j':
419cd74dd17STomasz Miąsko Type = BasicType::USize;
420cd74dd17STomasz Miąsko return true;
421cd74dd17STomasz Miąsko case 'l':
422cd74dd17STomasz Miąsko Type = BasicType::I32;
423cd74dd17STomasz Miąsko return true;
424cd74dd17STomasz Miąsko case 'm':
425cd74dd17STomasz Miąsko Type = BasicType::U32;
426cd74dd17STomasz Miąsko return true;
427cd74dd17STomasz Miąsko case 'n':
428cd74dd17STomasz Miąsko Type = BasicType::I128;
429cd74dd17STomasz Miąsko return true;
430cd74dd17STomasz Miąsko case 'o':
431cd74dd17STomasz Miąsko Type = BasicType::U128;
432cd74dd17STomasz Miąsko return true;
433cd74dd17STomasz Miąsko case 'p':
434cd74dd17STomasz Miąsko Type = BasicType::Placeholder;
435cd74dd17STomasz Miąsko return true;
436cd74dd17STomasz Miąsko case 's':
437cd74dd17STomasz Miąsko Type = BasicType::I16;
438cd74dd17STomasz Miąsko return true;
439cd74dd17STomasz Miąsko case 't':
440cd74dd17STomasz Miąsko Type = BasicType::U16;
441cd74dd17STomasz Miąsko return true;
442cd74dd17STomasz Miąsko case 'u':
443cd74dd17STomasz Miąsko Type = BasicType::Unit;
444cd74dd17STomasz Miąsko return true;
445cd74dd17STomasz Miąsko case 'v':
446cd74dd17STomasz Miąsko Type = BasicType::Variadic;
447cd74dd17STomasz Miąsko return true;
448cd74dd17STomasz Miąsko case 'x':
449cd74dd17STomasz Miąsko Type = BasicType::I64;
450cd74dd17STomasz Miąsko return true;
451cd74dd17STomasz Miąsko case 'y':
452cd74dd17STomasz Miąsko Type = BasicType::U64;
453cd74dd17STomasz Miąsko return true;
454cd74dd17STomasz Miąsko case 'z':
455cd74dd17STomasz Miąsko Type = BasicType::Never;
456cd74dd17STomasz Miąsko return true;
457cd74dd17STomasz Miąsko default:
458cd74dd17STomasz Miąsko return false;
459cd74dd17STomasz Miąsko }
460cd74dd17STomasz Miąsko }
461cd74dd17STomasz Miąsko
printBasicType(BasicType Type)462cd74dd17STomasz Miąsko void Demangler::printBasicType(BasicType Type) {
463cd74dd17STomasz Miąsko switch (Type) {
464cd74dd17STomasz Miąsko case BasicType::Bool:
465cd74dd17STomasz Miąsko print("bool");
466cd74dd17STomasz Miąsko break;
467cd74dd17STomasz Miąsko case BasicType::Char:
468cd74dd17STomasz Miąsko print("char");
469cd74dd17STomasz Miąsko break;
470cd74dd17STomasz Miąsko case BasicType::I8:
471cd74dd17STomasz Miąsko print("i8");
472cd74dd17STomasz Miąsko break;
473cd74dd17STomasz Miąsko case BasicType::I16:
474cd74dd17STomasz Miąsko print("i16");
475cd74dd17STomasz Miąsko break;
476cd74dd17STomasz Miąsko case BasicType::I32:
477cd74dd17STomasz Miąsko print("i32");
478cd74dd17STomasz Miąsko break;
479cd74dd17STomasz Miąsko case BasicType::I64:
480cd74dd17STomasz Miąsko print("i64");
481cd74dd17STomasz Miąsko break;
482cd74dd17STomasz Miąsko case BasicType::I128:
483cd74dd17STomasz Miąsko print("i128");
484cd74dd17STomasz Miąsko break;
485cd74dd17STomasz Miąsko case BasicType::ISize:
486cd74dd17STomasz Miąsko print("isize");
487cd74dd17STomasz Miąsko break;
488cd74dd17STomasz Miąsko case BasicType::U8:
489cd74dd17STomasz Miąsko print("u8");
490cd74dd17STomasz Miąsko break;
491cd74dd17STomasz Miąsko case BasicType::U16:
492cd74dd17STomasz Miąsko print("u16");
493cd74dd17STomasz Miąsko break;
494cd74dd17STomasz Miąsko case BasicType::U32:
495cd74dd17STomasz Miąsko print("u32");
496cd74dd17STomasz Miąsko break;
497cd74dd17STomasz Miąsko case BasicType::U64:
498cd74dd17STomasz Miąsko print("u64");
499cd74dd17STomasz Miąsko break;
500cd74dd17STomasz Miąsko case BasicType::U128:
501cd74dd17STomasz Miąsko print("u128");
502cd74dd17STomasz Miąsko break;
503cd74dd17STomasz Miąsko case BasicType::USize:
504cd74dd17STomasz Miąsko print("usize");
505cd74dd17STomasz Miąsko break;
506cd74dd17STomasz Miąsko case BasicType::F32:
507cd74dd17STomasz Miąsko print("f32");
508cd74dd17STomasz Miąsko break;
509cd74dd17STomasz Miąsko case BasicType::F64:
510cd74dd17STomasz Miąsko print("f64");
511cd74dd17STomasz Miąsko break;
512cd74dd17STomasz Miąsko case BasicType::Str:
513cd74dd17STomasz Miąsko print("str");
514cd74dd17STomasz Miąsko break;
515cd74dd17STomasz Miąsko case BasicType::Placeholder:
516cd74dd17STomasz Miąsko print("_");
517cd74dd17STomasz Miąsko break;
518cd74dd17STomasz Miąsko case BasicType::Unit:
519cd74dd17STomasz Miąsko print("()");
520cd74dd17STomasz Miąsko break;
521cd74dd17STomasz Miąsko case BasicType::Variadic:
522cd74dd17STomasz Miąsko print("...");
523cd74dd17STomasz Miąsko break;
524cd74dd17STomasz Miąsko case BasicType::Never:
525cd74dd17STomasz Miąsko print("!");
526cd74dd17STomasz Miąsko break;
527cd74dd17STomasz Miąsko }
5282961f863STomasz Miąsko }
5292961f863STomasz Miąsko
5302961f863STomasz Miąsko // <type> = | <basic-type>
5312961f863STomasz Miąsko // | <path> // named type
5322961f863STomasz Miąsko // | "A" <type> <const> // [T; N]
5332961f863STomasz Miąsko // | "S" <type> // [T]
5342961f863STomasz Miąsko // | "T" {<type>} "E" // (T1, T2, T3, ...)
5352961f863STomasz Miąsko // | "R" [<lifetime>] <type> // &T
5362961f863STomasz Miąsko // | "Q" [<lifetime>] <type> // &mut T
5372961f863STomasz Miąsko // | "P" <type> // *const T
5382961f863STomasz Miąsko // | "O" <type> // *mut T
5392961f863STomasz Miąsko // | "F" <fn-sig> // fn(...) -> ...
5402961f863STomasz Miąsko // | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a
5412961f863STomasz Miąsko // | <backref> // backref
demangleType()5422961f863STomasz Miąsko void Demangler::demangleType() {
54344d63c57STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) {
54444d63c57STomasz Miąsko Error = true;
54544d63c57STomasz Miąsko return;
54644d63c57STomasz Miąsko }
54751f6caf2SNathan Sidwell ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
54806833297STomasz Miąsko
54944d63c57STomasz Miąsko size_t Start = Position;
550b42400ccSTomasz Miąsko char C = consume();
551b42400ccSTomasz Miąsko BasicType Type;
552b42400ccSTomasz Miąsko if (parseBasicType(C, Type))
553b42400ccSTomasz Miąsko return printBasicType(Type);
554b42400ccSTomasz Miąsko
555b42400ccSTomasz Miąsko switch (C) {
556b42400ccSTomasz Miąsko case 'A':
557b42400ccSTomasz Miąsko print("[");
558b42400ccSTomasz Miąsko demangleType();
559b42400ccSTomasz Miąsko print("; ");
560b42400ccSTomasz Miąsko demangleConst();
561b42400ccSTomasz Miąsko print("]");
562b42400ccSTomasz Miąsko break;
563a84c65c2STomasz Miąsko case 'S':
564a84c65c2STomasz Miąsko print("[");
565a84c65c2STomasz Miąsko demangleType();
566a84c65c2STomasz Miąsko print("]");
567a84c65c2STomasz Miąsko break;
568774de7a0STomasz Miąsko case 'T': {
569774de7a0STomasz Miąsko print("(");
570774de7a0STomasz Miąsko size_t I = 0;
571774de7a0STomasz Miąsko for (; !Error && !consumeIf('E'); ++I) {
572774de7a0STomasz Miąsko if (I > 0)
573774de7a0STomasz Miąsko print(", ");
574774de7a0STomasz Miąsko demangleType();
575774de7a0STomasz Miąsko }
576774de7a0STomasz Miąsko if (I == 1)
577774de7a0STomasz Miąsko print(",");
578774de7a0STomasz Miąsko print(")");
579774de7a0STomasz Miąsko break;
580774de7a0STomasz Miąsko }
581e4fa6c95STomasz Miąsko case 'R':
582e4fa6c95STomasz Miąsko case 'Q':
583a67a234eSTomasz Miąsko print('&');
584a67a234eSTomasz Miąsko if (consumeIf('L')) {
585a67a234eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) {
586a67a234eSTomasz Miąsko printLifetime(Lifetime);
587a67a234eSTomasz Miąsko print(' ');
588a67a234eSTomasz Miąsko }
589a67a234eSTomasz Miąsko }
590a67a234eSTomasz Miąsko if (C == 'Q')
591a67a234eSTomasz Miąsko print("mut ");
592e4fa6c95STomasz Miąsko demangleType();
593e4fa6c95STomasz Miąsko break;
5946aac5633STomasz Miąsko case 'P':
5956aac5633STomasz Miąsko print("*const ");
5966aac5633STomasz Miąsko demangleType();
5976aac5633STomasz Miąsko break;
5986aac5633STomasz Miąsko case 'O':
5996aac5633STomasz Miąsko print("*mut ");
6006aac5633STomasz Miąsko demangleType();
6016aac5633STomasz Miąsko break;
60275cc1cf0STomasz Miąsko case 'F':
60375cc1cf0STomasz Miąsko demangleFnSig();
60475cc1cf0STomasz Miąsko break;
60589615a5eSTomasz Miąsko case 'D':
60689615a5eSTomasz Miąsko demangleDynBounds();
60789615a5eSTomasz Miąsko if (consumeIf('L')) {
60889615a5eSTomasz Miąsko if (auto Lifetime = parseBase62Number()) {
60989615a5eSTomasz Miąsko print(" + ");
61089615a5eSTomasz Miąsko printLifetime(Lifetime);
61189615a5eSTomasz Miąsko }
61289615a5eSTomasz Miąsko } else {
61389615a5eSTomasz Miąsko Error = true;
61489615a5eSTomasz Miąsko }
61589615a5eSTomasz Miąsko break;
61644d63c57STomasz Miąsko case 'B':
61744d63c57STomasz Miąsko demangleBackref([&] { demangleType(); });
61844d63c57STomasz Miąsko break;
619b42400ccSTomasz Miąsko default:
620b42400ccSTomasz Miąsko Position = Start;
6216cc6ada1STomasz Miąsko demanglePath(IsInType::Yes);
622b42400ccSTomasz Miąsko break;
623b42400ccSTomasz Miąsko }
624cd74dd17STomasz Miąsko }
625cd74dd17STomasz Miąsko
62675cc1cf0STomasz Miąsko // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type>
62775cc1cf0STomasz Miąsko // <abi> = "C"
62875cc1cf0STomasz Miąsko // | <undisambiguated-identifier>
demangleFnSig()62975cc1cf0STomasz Miąsko void Demangler::demangleFnSig() {
63051f6caf2SNathan Sidwell ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
631a67a234eSTomasz Miąsko demangleOptionalBinder();
63275cc1cf0STomasz Miąsko
63375cc1cf0STomasz Miąsko if (consumeIf('U'))
63475cc1cf0STomasz Miąsko print("unsafe ");
63575cc1cf0STomasz Miąsko
63675cc1cf0STomasz Miąsko if (consumeIf('K')) {
63775cc1cf0STomasz Miąsko print("extern \"");
63875cc1cf0STomasz Miąsko if (consumeIf('C')) {
63975cc1cf0STomasz Miąsko print("C");
64075cc1cf0STomasz Miąsko } else {
64175cc1cf0STomasz Miąsko Identifier Ident = parseIdentifier();
642c8c2b462STomasz Miąsko if (Ident.Punycode)
643c8c2b462STomasz Miąsko Error = true;
64475cc1cf0STomasz Miąsko for (char C : Ident.Name) {
64575cc1cf0STomasz Miąsko // When mangling ABI string, the "-" is replaced with "_".
64675cc1cf0STomasz Miąsko if (C == '_')
64775cc1cf0STomasz Miąsko C = '-';
64875cc1cf0STomasz Miąsko print(C);
64975cc1cf0STomasz Miąsko }
65075cc1cf0STomasz Miąsko }
65175cc1cf0STomasz Miąsko print("\" ");
65275cc1cf0STomasz Miąsko }
65375cc1cf0STomasz Miąsko
65475cc1cf0STomasz Miąsko print("fn(");
65575cc1cf0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
65675cc1cf0STomasz Miąsko if (I > 0)
65775cc1cf0STomasz Miąsko print(", ");
65875cc1cf0STomasz Miąsko demangleType();
65975cc1cf0STomasz Miąsko }
66075cc1cf0STomasz Miąsko print(")");
66175cc1cf0STomasz Miąsko
66275cc1cf0STomasz Miąsko if (consumeIf('u')) {
66375cc1cf0STomasz Miąsko // Skip the unit type from the output.
66475cc1cf0STomasz Miąsko } else {
66575cc1cf0STomasz Miąsko print(" -> ");
66675cc1cf0STomasz Miąsko demangleType();
66775cc1cf0STomasz Miąsko }
66875cc1cf0STomasz Miąsko }
66975cc1cf0STomasz Miąsko
67089615a5eSTomasz Miąsko // <dyn-bounds> = [<binder>] {<dyn-trait>} "E"
demangleDynBounds()67189615a5eSTomasz Miąsko void Demangler::demangleDynBounds() {
67251f6caf2SNathan Sidwell ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
67389615a5eSTomasz Miąsko print("dyn ");
67489615a5eSTomasz Miąsko demangleOptionalBinder();
6751499afa0STomasz Miąsko for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
6761499afa0STomasz Miąsko if (I > 0)
6771499afa0STomasz Miąsko print(" + ");
6781499afa0STomasz Miąsko demangleDynTrait();
6791499afa0STomasz Miąsko }
6801499afa0STomasz Miąsko }
6811499afa0STomasz Miąsko
6821499afa0STomasz Miąsko // <dyn-trait> = <path> {<dyn-trait-assoc-binding>}
6831499afa0STomasz Miąsko // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type>
demangleDynTrait()6841499afa0STomasz Miąsko void Demangler::demangleDynTrait() {
6856cc6ada1STomasz Miąsko bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes);
686619a65e5STomasz Miąsko while (!Error && consumeIf('p')) {
687619a65e5STomasz Miąsko if (!IsOpen) {
688619a65e5STomasz Miąsko IsOpen = true;
689619a65e5STomasz Miąsko print('<');
690619a65e5STomasz Miąsko } else {
691619a65e5STomasz Miąsko print(", ");
692619a65e5STomasz Miąsko }
693619a65e5STomasz Miąsko print(parseIdentifier().Name);
694619a65e5STomasz Miąsko print(" = ");
695619a65e5STomasz Miąsko demangleType();
696619a65e5STomasz Miąsko }
697619a65e5STomasz Miąsko if (IsOpen)
698619a65e5STomasz Miąsko print(">");
69989615a5eSTomasz Miąsko }
70089615a5eSTomasz Miąsko
701a67a234eSTomasz Miąsko // Demangles optional binder and updates the number of bound lifetimes.
702a67a234eSTomasz Miąsko //
703a67a234eSTomasz Miąsko // <binder> = "G" <base-62-number>
demangleOptionalBinder()704a67a234eSTomasz Miąsko void Demangler::demangleOptionalBinder() {
705a67a234eSTomasz Miąsko uint64_t Binder = parseOptionalBase62Number('G');
706a67a234eSTomasz Miąsko if (Error || Binder == 0)
707a67a234eSTomasz Miąsko return;
708a67a234eSTomasz Miąsko
709a67a234eSTomasz Miąsko // In valid inputs each bound lifetime is referenced later. Referencing a
710a67a234eSTomasz Miąsko // lifetime requires at least one byte of input. Reject inputs that are too
711a67a234eSTomasz Miąsko // short to reference all bound lifetimes. Otherwise demangling of invalid
712a67a234eSTomasz Miąsko // binders could generate excessive amounts of output.
713a67a234eSTomasz Miąsko if (Binder >= Input.size() - BoundLifetimes) {
714a67a234eSTomasz Miąsko Error = true;
715a67a234eSTomasz Miąsko return;
716a67a234eSTomasz Miąsko }
717a67a234eSTomasz Miąsko
718a67a234eSTomasz Miąsko print("for<");
719a67a234eSTomasz Miąsko for (size_t I = 0; I != Binder; ++I) {
720a67a234eSTomasz Miąsko BoundLifetimes += 1;
721a67a234eSTomasz Miąsko if (I > 0)
722a67a234eSTomasz Miąsko print(", ");
723a67a234eSTomasz Miąsko printLifetime(1);
724a67a234eSTomasz Miąsko }
725a67a234eSTomasz Miąsko print("> ");
726a67a234eSTomasz Miąsko }
727a67a234eSTomasz Miąsko
728cd74dd17STomasz Miąsko // <const> = <basic-type> <const-data>
729cd74dd17STomasz Miąsko // | "p" // placeholder
730cd74dd17STomasz Miąsko // | <backref>
demangleConst()731cd74dd17STomasz Miąsko void Demangler::demangleConst() {
732f9a79356STomasz Miąsko if (Error || RecursionLevel >= MaxRecursionLevel) {
733f9a79356STomasz Miąsko Error = true;
734f9a79356STomasz Miąsko return;
735f9a79356STomasz Miąsko }
73651f6caf2SNathan Sidwell ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
737f9a79356STomasz Miąsko
738f9a79356STomasz Miąsko char C = consume();
739cd74dd17STomasz Miąsko BasicType Type;
740f9a79356STomasz Miąsko if (parseBasicType(C, Type)) {
741cd74dd17STomasz Miąsko switch (Type) {
742cd74dd17STomasz Miąsko case BasicType::I8:
743cd74dd17STomasz Miąsko case BasicType::I16:
744cd74dd17STomasz Miąsko case BasicType::I32:
745cd74dd17STomasz Miąsko case BasicType::I64:
746cd74dd17STomasz Miąsko case BasicType::I128:
747cd74dd17STomasz Miąsko case BasicType::ISize:
748cd74dd17STomasz Miąsko case BasicType::U8:
749cd74dd17STomasz Miąsko case BasicType::U16:
750cd74dd17STomasz Miąsko case BasicType::U32:
751cd74dd17STomasz Miąsko case BasicType::U64:
752cd74dd17STomasz Miąsko case BasicType::U128:
753cd74dd17STomasz Miąsko case BasicType::USize:
754cd74dd17STomasz Miąsko demangleConstInt();
755cd74dd17STomasz Miąsko break;
756fc0f2bb9STomasz Miąsko case BasicType::Bool:
757fc0f2bb9STomasz Miąsko demangleConstBool();
758fc0f2bb9STomasz Miąsko break;
7592ba49f6aSTomasz Miąsko case BasicType::Char:
7602ba49f6aSTomasz Miąsko demangleConstChar();
7612ba49f6aSTomasz Miąsko break;
762cd74dd17STomasz Miąsko case BasicType::Placeholder:
763cd74dd17STomasz Miąsko print('_');
764cd74dd17STomasz Miąsko break;
765cd74dd17STomasz Miąsko default:
7662961f863STomasz Miąsko Error = true;
767cd74dd17STomasz Miąsko break;
768cd74dd17STomasz Miąsko }
769f9a79356STomasz Miąsko } else if (C == 'B') {
770f9a79356STomasz Miąsko demangleBackref([&] { demangleConst(); });
771cd74dd17STomasz Miąsko } else {
772cd74dd17STomasz Miąsko Error = true;
773cd74dd17STomasz Miąsko }
774cd74dd17STomasz Miąsko }
775cd74dd17STomasz Miąsko
776cd74dd17STomasz Miąsko // <const-data> = ["n"] <hex-number>
demangleConstInt()777cd74dd17STomasz Miąsko void Demangler::demangleConstInt() {
778cd74dd17STomasz Miąsko if (consumeIf('n'))
779cd74dd17STomasz Miąsko print('-');
780cd74dd17STomasz Miąsko
781cd74dd17STomasz Miąsko StringView HexDigits;
782cd74dd17STomasz Miąsko uint64_t Value = parseHexNumber(HexDigits);
783cd74dd17STomasz Miąsko if (HexDigits.size() <= 16) {
784cd74dd17STomasz Miąsko printDecimalNumber(Value);
785cd74dd17STomasz Miąsko } else {
786cd74dd17STomasz Miąsko print("0x");
787cd74dd17STomasz Miąsko print(HexDigits);
7882961f863STomasz Miąsko }
7892961f863STomasz Miąsko }
7902961f863STomasz Miąsko
791fc0f2bb9STomasz Miąsko // <const-data> = "0_" // false
792fc0f2bb9STomasz Miąsko // | "1_" // true
demangleConstBool()793fc0f2bb9STomasz Miąsko void Demangler::demangleConstBool() {
794fc0f2bb9STomasz Miąsko StringView HexDigits;
795fc0f2bb9STomasz Miąsko parseHexNumber(HexDigits);
796fc0f2bb9STomasz Miąsko if (HexDigits == "0")
797fc0f2bb9STomasz Miąsko print("false");
798fc0f2bb9STomasz Miąsko else if (HexDigits == "1")
799fc0f2bb9STomasz Miąsko print("true");
800fc0f2bb9STomasz Miąsko else
801fc0f2bb9STomasz Miąsko Error = true;
802fc0f2bb9STomasz Miąsko }
803fc0f2bb9STomasz Miąsko
8042ba49f6aSTomasz Miąsko /// Returns true if CodePoint represents a printable ASCII character.
isAsciiPrintable(uint64_t CodePoint)8052ba49f6aSTomasz Miąsko static bool isAsciiPrintable(uint64_t CodePoint) {
8062ba49f6aSTomasz Miąsko return 0x20 <= CodePoint && CodePoint <= 0x7e;
8072ba49f6aSTomasz Miąsko }
8082ba49f6aSTomasz Miąsko
8092ba49f6aSTomasz Miąsko // <const-data> = <hex-number>
demangleConstChar()8102ba49f6aSTomasz Miąsko void Demangler::demangleConstChar() {
8112ba49f6aSTomasz Miąsko StringView HexDigits;
8122ba49f6aSTomasz Miąsko uint64_t CodePoint = parseHexNumber(HexDigits);
8132ba49f6aSTomasz Miąsko if (Error || HexDigits.size() > 6) {
8142ba49f6aSTomasz Miąsko Error = true;
8152ba49f6aSTomasz Miąsko return;
8162ba49f6aSTomasz Miąsko }
8172ba49f6aSTomasz Miąsko
8182ba49f6aSTomasz Miąsko print("'");
8192ba49f6aSTomasz Miąsko switch (CodePoint) {
8202ba49f6aSTomasz Miąsko case '\t':
8212ba49f6aSTomasz Miąsko print(R"(\t)");
8222ba49f6aSTomasz Miąsko break;
8232ba49f6aSTomasz Miąsko case '\r':
8242ba49f6aSTomasz Miąsko print(R"(\r)");
8252ba49f6aSTomasz Miąsko break;
8262ba49f6aSTomasz Miąsko case '\n':
8272ba49f6aSTomasz Miąsko print(R"(\n)");
8282ba49f6aSTomasz Miąsko break;
8292ba49f6aSTomasz Miąsko case '\\':
8302ba49f6aSTomasz Miąsko print(R"(\\)");
8312ba49f6aSTomasz Miąsko break;
8322ba49f6aSTomasz Miąsko case '"':
8332ba49f6aSTomasz Miąsko print(R"(")");
8342ba49f6aSTomasz Miąsko break;
8352ba49f6aSTomasz Miąsko case '\'':
8362ba49f6aSTomasz Miąsko print(R"(\')");
8372ba49f6aSTomasz Miąsko break;
8382ba49f6aSTomasz Miąsko default:
8392ba49f6aSTomasz Miąsko if (isAsciiPrintable(CodePoint)) {
8402ba49f6aSTomasz Miąsko char C = CodePoint;
8412ba49f6aSTomasz Miąsko print(C);
8422ba49f6aSTomasz Miąsko } else {
8432ba49f6aSTomasz Miąsko print(R"(\u{)");
8442ba49f6aSTomasz Miąsko print(HexDigits);
8452ba49f6aSTomasz Miąsko print('}');
8462ba49f6aSTomasz Miąsko }
8472ba49f6aSTomasz Miąsko break;
8482ba49f6aSTomasz Miąsko }
8492ba49f6aSTomasz Miąsko print('\'');
8502ba49f6aSTomasz Miąsko }
8512ba49f6aSTomasz Miąsko
8527310403eSTomasz Miąsko // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes>
parseIdentifier()8537310403eSTomasz Miąsko Identifier Demangler::parseIdentifier() {
8547310403eSTomasz Miąsko bool Punycode = consumeIf('u');
8557310403eSTomasz Miąsko uint64_t Bytes = parseDecimalNumber();
8567310403eSTomasz Miąsko
8577310403eSTomasz Miąsko // Underscore resolves the ambiguity when identifier starts with a decimal
8587310403eSTomasz Miąsko // digit or another underscore.
8597310403eSTomasz Miąsko consumeIf('_');
8607310403eSTomasz Miąsko
8617310403eSTomasz Miąsko if (Error || Bytes > Input.size() - Position) {
8627310403eSTomasz Miąsko Error = true;
8637310403eSTomasz Miąsko return {};
8647310403eSTomasz Miąsko }
8657310403eSTomasz Miąsko StringView S = Input.substr(Position, Bytes);
8667310403eSTomasz Miąsko Position += Bytes;
8677310403eSTomasz Miąsko
8687310403eSTomasz Miąsko if (!std::all_of(S.begin(), S.end(), isValid)) {
8697310403eSTomasz Miąsko Error = true;
8707310403eSTomasz Miąsko return {};
8717310403eSTomasz Miąsko }
8727310403eSTomasz Miąsko
8737310403eSTomasz Miąsko return {S, Punycode};
8747310403eSTomasz Miąsko }
8757310403eSTomasz Miąsko
8767310403eSTomasz Miąsko // Parses optional base 62 number. The presence of a number is determined using
877a67a234eSTomasz Miąsko // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise
878a67a234eSTomasz Miąsko //
879a67a234eSTomasz Miąsko // This function is indended for parsing disambiguators and binders which when
880a67a234eSTomasz Miąsko // not present have their value interpreted as 0, and otherwise as decoded
881a67a234eSTomasz Miąsko // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is
882a67a234eSTomasz Miąsko // 2. When "G" is absent value is 0.
parseOptionalBase62Number(char Tag)88378e94915STomasz Miąsko uint64_t Demangler::parseOptionalBase62Number(char Tag) {
88478e94915STomasz Miąsko if (!consumeIf(Tag))
88578e94915STomasz Miąsko return 0;
88678e94915STomasz Miąsko
88778e94915STomasz Miąsko uint64_t N = parseBase62Number();
88878e94915STomasz Miąsko if (Error || !addAssign(N, 1))
88978e94915STomasz Miąsko return 0;
89078e94915STomasz Miąsko
89178e94915STomasz Miąsko return N;
8927310403eSTomasz Miąsko }
8937310403eSTomasz Miąsko
8947310403eSTomasz Miąsko // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by
8957310403eSTomasz Miąsko // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1,
8967310403eSTomasz Miąsko // "1_" encodes 2, etc.
8977310403eSTomasz Miąsko //
8987310403eSTomasz Miąsko // <base-62-number> = {<0-9a-zA-Z>} "_"
parseBase62Number()8997310403eSTomasz Miąsko uint64_t Demangler::parseBase62Number() {
9007310403eSTomasz Miąsko if (consumeIf('_'))
9017310403eSTomasz Miąsko return 0;
9027310403eSTomasz Miąsko
9037310403eSTomasz Miąsko uint64_t Value = 0;
9047310403eSTomasz Miąsko
9057310403eSTomasz Miąsko while (true) {
9067310403eSTomasz Miąsko uint64_t Digit;
9077310403eSTomasz Miąsko char C = consume();
9087310403eSTomasz Miąsko
9097310403eSTomasz Miąsko if (C == '_') {
9107310403eSTomasz Miąsko break;
9117310403eSTomasz Miąsko } else if (isDigit(C)) {
9127310403eSTomasz Miąsko Digit = C - '0';
9137310403eSTomasz Miąsko } else if (isLower(C)) {
9147310403eSTomasz Miąsko Digit = 10 + (C - 'a');
9157310403eSTomasz Miąsko } else if (isUpper(C)) {
9167310403eSTomasz Miąsko Digit = 10 + 26 + (C - 'A');
9177310403eSTomasz Miąsko } else {
9187310403eSTomasz Miąsko Error = true;
9197310403eSTomasz Miąsko return 0;
9207310403eSTomasz Miąsko }
9217310403eSTomasz Miąsko
9227310403eSTomasz Miąsko if (!mulAssign(Value, 62))
9237310403eSTomasz Miąsko return 0;
9247310403eSTomasz Miąsko
9257310403eSTomasz Miąsko if (!addAssign(Value, Digit))
9267310403eSTomasz Miąsko return 0;
9277310403eSTomasz Miąsko }
9287310403eSTomasz Miąsko
9297310403eSTomasz Miąsko if (!addAssign(Value, 1))
9307310403eSTomasz Miąsko return 0;
9317310403eSTomasz Miąsko
9327310403eSTomasz Miąsko return Value;
9337310403eSTomasz Miąsko }
9347310403eSTomasz Miąsko
9357310403eSTomasz Miąsko // Parses a decimal number that had been encoded without any leading zeros.
9367310403eSTomasz Miąsko //
9377310403eSTomasz Miąsko // <decimal-number> = "0"
9387310403eSTomasz Miąsko // | <1-9> {<0-9>}
parseDecimalNumber()9397310403eSTomasz Miąsko uint64_t Demangler::parseDecimalNumber() {
9407310403eSTomasz Miąsko char C = look();
9417310403eSTomasz Miąsko if (!isDigit(C)) {
9427310403eSTomasz Miąsko Error = true;
9437310403eSTomasz Miąsko return 0;
9447310403eSTomasz Miąsko }
9457310403eSTomasz Miąsko
9467310403eSTomasz Miąsko if (C == '0') {
9477310403eSTomasz Miąsko consume();
9487310403eSTomasz Miąsko return 0;
9497310403eSTomasz Miąsko }
9507310403eSTomasz Miąsko
9517310403eSTomasz Miąsko uint64_t Value = 0;
9527310403eSTomasz Miąsko
9537310403eSTomasz Miąsko while (isDigit(look())) {
9547310403eSTomasz Miąsko if (!mulAssign(Value, 10)) {
9557310403eSTomasz Miąsko Error = true;
9567310403eSTomasz Miąsko return 0;
9577310403eSTomasz Miąsko }
9587310403eSTomasz Miąsko
9597310403eSTomasz Miąsko uint64_t D = consume() - '0';
9607310403eSTomasz Miąsko if (!addAssign(Value, D))
9617310403eSTomasz Miąsko return 0;
9627310403eSTomasz Miąsko }
9637310403eSTomasz Miąsko
9647310403eSTomasz Miąsko return Value;
9657310403eSTomasz Miąsko }
966cd74dd17STomasz Miąsko
967cd74dd17STomasz Miąsko // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed
968cd74dd17STomasz Miąsko // value and stores hex digits in HexDigits. The return value is unspecified if
969cd74dd17STomasz Miąsko // HexDigits.size() > 16.
970cd74dd17STomasz Miąsko //
971cd74dd17STomasz Miąsko // <hex-number> = "0_"
972cd74dd17STomasz Miąsko // | <1-9a-f> {<0-9a-f>} "_"
parseHexNumber(StringView & HexDigits)973cd74dd17STomasz Miąsko uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
974cd74dd17STomasz Miąsko size_t Start = Position;
975cd74dd17STomasz Miąsko uint64_t Value = 0;
976cd74dd17STomasz Miąsko
977cd74dd17STomasz Miąsko if (!isHexDigit(look()))
978cd74dd17STomasz Miąsko Error = true;
979cd74dd17STomasz Miąsko
980cd74dd17STomasz Miąsko if (consumeIf('0')) {
981cd74dd17STomasz Miąsko if (!consumeIf('_'))
982cd74dd17STomasz Miąsko Error = true;
983cd74dd17STomasz Miąsko } else {
984cd74dd17STomasz Miąsko while (!Error && !consumeIf('_')) {
985cd74dd17STomasz Miąsko char C = consume();
986cd74dd17STomasz Miąsko Value *= 16;
987cd74dd17STomasz Miąsko if (isDigit(C))
988cd74dd17STomasz Miąsko Value += C - '0';
989cd74dd17STomasz Miąsko else if ('a' <= C && C <= 'f')
990cd74dd17STomasz Miąsko Value += 10 + (C - 'a');
991cd74dd17STomasz Miąsko else
992cd74dd17STomasz Miąsko Error = true;
993cd74dd17STomasz Miąsko }
994cd74dd17STomasz Miąsko }
995cd74dd17STomasz Miąsko
996cd74dd17STomasz Miąsko if (Error) {
997cd74dd17STomasz Miąsko HexDigits = StringView();
998cd74dd17STomasz Miąsko return 0;
999cd74dd17STomasz Miąsko }
1000cd74dd17STomasz Miąsko
1001cd74dd17STomasz Miąsko size_t End = Position - 1;
1002cd74dd17STomasz Miąsko assert(Start < End);
1003cd74dd17STomasz Miąsko HexDigits = Input.substr(Start, End - Start);
1004cd74dd17STomasz Miąsko return Value;
1005cd74dd17STomasz Miąsko }
1006a67a234eSTomasz Miąsko
print(char C)10076cc6ada1STomasz Miąsko void Demangler::print(char C) {
10086cc6ada1STomasz Miąsko if (Error || !Print)
10096cc6ada1STomasz Miąsko return;
10106cc6ada1STomasz Miąsko
10116cc6ada1STomasz Miąsko Output += C;
10126cc6ada1STomasz Miąsko }
10136cc6ada1STomasz Miąsko
print(StringView S)10146cc6ada1STomasz Miąsko void Demangler::print(StringView S) {
10156cc6ada1STomasz Miąsko if (Error || !Print)
10166cc6ada1STomasz Miąsko return;
10176cc6ada1STomasz Miąsko
10186cc6ada1STomasz Miąsko Output += S;
10196cc6ada1STomasz Miąsko }
10206cc6ada1STomasz Miąsko
printDecimalNumber(uint64_t N)10216cc6ada1STomasz Miąsko void Demangler::printDecimalNumber(uint64_t N) {
10226cc6ada1STomasz Miąsko if (Error || !Print)
10236cc6ada1STomasz Miąsko return;
10246cc6ada1STomasz Miąsko
10256cc6ada1STomasz Miąsko Output << N;
10266cc6ada1STomasz Miąsko }
10276cc6ada1STomasz Miąsko
1028a67a234eSTomasz Miąsko // Prints a lifetime. An index 0 always represents an erased lifetime. Indices
1029a67a234eSTomasz Miąsko // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes
1030a67a234eSTomasz Miąsko // bound by one of the enclosing binders.
printLifetime(uint64_t Index)1031a67a234eSTomasz Miąsko void Demangler::printLifetime(uint64_t Index) {
1032a67a234eSTomasz Miąsko if (Index == 0) {
1033a67a234eSTomasz Miąsko print("'_");
1034a67a234eSTomasz Miąsko return;
1035a67a234eSTomasz Miąsko }
1036a67a234eSTomasz Miąsko
1037a67a234eSTomasz Miąsko if (Index - 1 >= BoundLifetimes) {
1038a67a234eSTomasz Miąsko Error = true;
1039a67a234eSTomasz Miąsko return;
1040a67a234eSTomasz Miąsko }
1041a67a234eSTomasz Miąsko
1042a67a234eSTomasz Miąsko uint64_t Depth = BoundLifetimes - Index;
1043a67a234eSTomasz Miąsko print('\'');
1044a67a234eSTomasz Miąsko if (Depth < 26) {
1045a67a234eSTomasz Miąsko char C = 'a' + Depth;
1046a67a234eSTomasz Miąsko print(C);
1047a67a234eSTomasz Miąsko } else {
1048a67a234eSTomasz Miąsko print('z');
1049a67a234eSTomasz Miąsko printDecimalNumber(Depth - 26 + 1);
1050a67a234eSTomasz Miąsko }
1051a67a234eSTomasz Miąsko }
10526cc6ada1STomasz Miąsko
decodePunycodeDigit(char C,size_t & Value)1053c8c2b462STomasz Miąsko static inline bool decodePunycodeDigit(char C, size_t &Value) {
1054c8c2b462STomasz Miąsko if (isLower(C)) {
1055c8c2b462STomasz Miąsko Value = C - 'a';
1056c8c2b462STomasz Miąsko return true;
1057c8c2b462STomasz Miąsko }
1058c8c2b462STomasz Miąsko
1059c8c2b462STomasz Miąsko if (isDigit(C)) {
1060c8c2b462STomasz Miąsko Value = 26 + (C - '0');
1061c8c2b462STomasz Miąsko return true;
1062c8c2b462STomasz Miąsko }
1063c8c2b462STomasz Miąsko
1064c8c2b462STomasz Miąsko return false;
1065c8c2b462STomasz Miąsko }
1066c8c2b462STomasz Miąsko
removeNullBytes(OutputBuffer & Output,size_t StartIdx)10672e97236aSLuís Ferreira static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) {
1068c8c2b462STomasz Miąsko char *Buffer = Output.getBuffer();
1069c8c2b462STomasz Miąsko char *Start = Buffer + StartIdx;
1070c8c2b462STomasz Miąsko char *End = Buffer + Output.getCurrentPosition();
1071c8c2b462STomasz Miąsko Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer);
1072c8c2b462STomasz Miąsko }
1073c8c2b462STomasz Miąsko
1074c8c2b462STomasz Miąsko // Encodes code point as UTF-8 and stores results in Output. Returns false if
1075c8c2b462STomasz Miąsko // CodePoint is not a valid unicode scalar value.
encodeUTF8(size_t CodePoint,char * Output)1076c8c2b462STomasz Miąsko static inline bool encodeUTF8(size_t CodePoint, char *Output) {
1077c8c2b462STomasz Miąsko if (0xD800 <= CodePoint && CodePoint <= 0xDFFF)
1078c8c2b462STomasz Miąsko return false;
1079c8c2b462STomasz Miąsko
1080c8c2b462STomasz Miąsko if (CodePoint <= 0x7F) {
1081c8c2b462STomasz Miąsko Output[0] = CodePoint;
1082c8c2b462STomasz Miąsko return true;
1083c8c2b462STomasz Miąsko }
1084c8c2b462STomasz Miąsko
1085c8c2b462STomasz Miąsko if (CodePoint <= 0x7FF) {
1086c8c2b462STomasz Miąsko Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F);
1087c8c2b462STomasz Miąsko Output[1] = 0x80 | (CodePoint & 0x3F);
1088c8c2b462STomasz Miąsko return true;
1089c8c2b462STomasz Miąsko }
1090c8c2b462STomasz Miąsko
1091c8c2b462STomasz Miąsko if (CodePoint <= 0xFFFF) {
1092c8c2b462STomasz Miąsko Output[0] = 0xE0 | (CodePoint >> 12);
1093c8c2b462STomasz Miąsko Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F);
1094c8c2b462STomasz Miąsko Output[2] = 0x80 | (CodePoint & 0x3F);
1095c8c2b462STomasz Miąsko return true;
1096c8c2b462STomasz Miąsko }
1097c8c2b462STomasz Miąsko
1098c8c2b462STomasz Miąsko if (CodePoint <= 0x10FFFF) {
1099c8c2b462STomasz Miąsko Output[0] = 0xF0 | (CodePoint >> 18);
1100c8c2b462STomasz Miąsko Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F);
1101c8c2b462STomasz Miąsko Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F);
1102c8c2b462STomasz Miąsko Output[3] = 0x80 | (CodePoint & 0x3F);
1103c8c2b462STomasz Miąsko return true;
1104c8c2b462STomasz Miąsko }
1105c8c2b462STomasz Miąsko
1106c8c2b462STomasz Miąsko return false;
1107c8c2b462STomasz Miąsko }
1108c8c2b462STomasz Miąsko
1109c8c2b462STomasz Miąsko // Decodes string encoded using punycode and appends results to Output.
1110c8c2b462STomasz Miąsko // Returns true if decoding was successful.
decodePunycode(StringView Input,OutputBuffer & Output)11112e97236aSLuís Ferreira static bool decodePunycode(StringView Input, OutputBuffer &Output) {
1112c8c2b462STomasz Miąsko size_t OutputSize = Output.getCurrentPosition();
1113c8c2b462STomasz Miąsko size_t InputIdx = 0;
1114c8c2b462STomasz Miąsko
1115c8c2b462STomasz Miąsko // Rust uses an underscore as a delimiter.
1116c8c2b462STomasz Miąsko size_t DelimiterPos = StringView::npos;
1117c8c2b462STomasz Miąsko for (size_t I = 0; I != Input.size(); ++I)
1118c8c2b462STomasz Miąsko if (Input[I] == '_')
1119c8c2b462STomasz Miąsko DelimiterPos = I;
1120c8c2b462STomasz Miąsko
1121c8c2b462STomasz Miąsko if (DelimiterPos != StringView::npos) {
1122c8c2b462STomasz Miąsko // Copy basic code points before the last delimiter to the output.
1123c8c2b462STomasz Miąsko for (; InputIdx != DelimiterPos; ++InputIdx) {
1124c8c2b462STomasz Miąsko char C = Input[InputIdx];
1125c8c2b462STomasz Miąsko if (!isValid(C))
1126c8c2b462STomasz Miąsko return false;
1127c8c2b462STomasz Miąsko // Code points are padded with zeros while decoding is in progress.
1128c8c2b462STomasz Miąsko char UTF8[4] = {C};
1129c8c2b462STomasz Miąsko Output += StringView(UTF8, UTF8 + 4);
1130c8c2b462STomasz Miąsko }
1131c8c2b462STomasz Miąsko // Skip over the delimiter.
1132c8c2b462STomasz Miąsko ++InputIdx;
1133c8c2b462STomasz Miąsko }
1134c8c2b462STomasz Miąsko
1135c8c2b462STomasz Miąsko size_t Base = 36;
1136c8c2b462STomasz Miąsko size_t Skew = 38;
1137c8c2b462STomasz Miąsko size_t Bias = 72;
1138c8c2b462STomasz Miąsko size_t N = 0x80;
1139c8c2b462STomasz Miąsko size_t TMin = 1;
1140c8c2b462STomasz Miąsko size_t TMax = 26;
1141c8c2b462STomasz Miąsko size_t Damp = 700;
1142c8c2b462STomasz Miąsko
1143c8c2b462STomasz Miąsko auto Adapt = [&](size_t Delta, size_t NumPoints) {
1144c8c2b462STomasz Miąsko Delta /= Damp;
1145c8c2b462STomasz Miąsko Delta += Delta / NumPoints;
1146c8c2b462STomasz Miąsko Damp = 2;
1147c8c2b462STomasz Miąsko
1148c8c2b462STomasz Miąsko size_t K = 0;
1149c8c2b462STomasz Miąsko while (Delta > (Base - TMin) * TMax / 2) {
1150c8c2b462STomasz Miąsko Delta /= Base - TMin;
1151c8c2b462STomasz Miąsko K += Base;
1152c8c2b462STomasz Miąsko }
1153c8c2b462STomasz Miąsko return K + (((Base - TMin + 1) * Delta) / (Delta + Skew));
1154c8c2b462STomasz Miąsko };
1155c8c2b462STomasz Miąsko
1156c8c2b462STomasz Miąsko // Main decoding loop.
1157c8c2b462STomasz Miąsko for (size_t I = 0; InputIdx != Input.size(); I += 1) {
1158c8c2b462STomasz Miąsko size_t OldI = I;
1159c8c2b462STomasz Miąsko size_t W = 1;
1160c8c2b462STomasz Miąsko size_t Max = std::numeric_limits<size_t>::max();
1161c8c2b462STomasz Miąsko for (size_t K = Base; true; K += Base) {
1162c8c2b462STomasz Miąsko if (InputIdx == Input.size())
1163c8c2b462STomasz Miąsko return false;
1164c8c2b462STomasz Miąsko char C = Input[InputIdx++];
1165c8c2b462STomasz Miąsko size_t Digit = 0;
1166c8c2b462STomasz Miąsko if (!decodePunycodeDigit(C, Digit))
1167c8c2b462STomasz Miąsko return false;
1168c8c2b462STomasz Miąsko
1169c8c2b462STomasz Miąsko if (Digit > (Max - I) / W)
1170c8c2b462STomasz Miąsko return false;
1171c8c2b462STomasz Miąsko I += Digit * W;
1172c8c2b462STomasz Miąsko
1173c8c2b462STomasz Miąsko size_t T;
1174c8c2b462STomasz Miąsko if (K <= Bias)
1175c8c2b462STomasz Miąsko T = TMin;
1176c8c2b462STomasz Miąsko else if (K >= Bias + TMax)
1177c8c2b462STomasz Miąsko T = TMax;
1178c8c2b462STomasz Miąsko else
1179c8c2b462STomasz Miąsko T = K - Bias;
1180c8c2b462STomasz Miąsko
1181c8c2b462STomasz Miąsko if (Digit < T)
1182c8c2b462STomasz Miąsko break;
1183c8c2b462STomasz Miąsko
1184c8c2b462STomasz Miąsko if (W > Max / (Base - T))
1185c8c2b462STomasz Miąsko return false;
1186c8c2b462STomasz Miąsko W *= (Base - T);
1187c8c2b462STomasz Miąsko }
1188c8c2b462STomasz Miąsko size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1;
1189c8c2b462STomasz Miąsko Bias = Adapt(I - OldI, NumPoints);
1190c8c2b462STomasz Miąsko
1191c8c2b462STomasz Miąsko if (I / NumPoints > Max - N)
1192c8c2b462STomasz Miąsko return false;
1193c8c2b462STomasz Miąsko N += I / NumPoints;
1194c8c2b462STomasz Miąsko I = I % NumPoints;
1195c8c2b462STomasz Miąsko
1196c8c2b462STomasz Miąsko // Insert N at position I in the output.
1197c8c2b462STomasz Miąsko char UTF8[4] = {};
1198c8c2b462STomasz Miąsko if (!encodeUTF8(N, UTF8))
1199c8c2b462STomasz Miąsko return false;
1200c8c2b462STomasz Miąsko Output.insert(OutputSize + I * 4, UTF8, 4);
1201c8c2b462STomasz Miąsko }
1202c8c2b462STomasz Miąsko
1203c8c2b462STomasz Miąsko removeNullBytes(Output, OutputSize);
1204c8c2b462STomasz Miąsko return true;
1205c8c2b462STomasz Miąsko }
1206c8c2b462STomasz Miąsko
printIdentifier(Identifier Ident)1207c8c2b462STomasz Miąsko void Demangler::printIdentifier(Identifier Ident) {
1208c8c2b462STomasz Miąsko if (Error || !Print)
1209c8c2b462STomasz Miąsko return;
1210c8c2b462STomasz Miąsko
1211c8c2b462STomasz Miąsko if (Ident.Punycode) {
1212c8c2b462STomasz Miąsko if (!decodePunycode(Ident.Name, Output))
1213c8c2b462STomasz Miąsko Error = true;
1214c8c2b462STomasz Miąsko } else {
1215c8c2b462STomasz Miąsko print(Ident.Name);
1216c8c2b462STomasz Miąsko }
1217c8c2b462STomasz Miąsko }
1218c8c2b462STomasz Miąsko
look() const12196cc6ada1STomasz Miąsko char Demangler::look() const {
12206cc6ada1STomasz Miąsko if (Error || Position >= Input.size())
12216cc6ada1STomasz Miąsko return 0;
12226cc6ada1STomasz Miąsko
12236cc6ada1STomasz Miąsko return Input[Position];
12246cc6ada1STomasz Miąsko }
12256cc6ada1STomasz Miąsko
consume()12266cc6ada1STomasz Miąsko char Demangler::consume() {
12276cc6ada1STomasz Miąsko if (Error || Position >= Input.size()) {
12286cc6ada1STomasz Miąsko Error = true;
12296cc6ada1STomasz Miąsko return 0;
12306cc6ada1STomasz Miąsko }
12316cc6ada1STomasz Miąsko
12326cc6ada1STomasz Miąsko return Input[Position++];
12336cc6ada1STomasz Miąsko }
12346cc6ada1STomasz Miąsko
consumeIf(char Prefix)12356cc6ada1STomasz Miąsko bool Demangler::consumeIf(char Prefix) {
12366cc6ada1STomasz Miąsko if (Error || Position >= Input.size() || Input[Position] != Prefix)
12376cc6ada1STomasz Miąsko return false;
12386cc6ada1STomasz Miąsko
12396cc6ada1STomasz Miąsko Position += 1;
12406cc6ada1STomasz Miąsko return true;
12416cc6ada1STomasz Miąsko }
12426cc6ada1STomasz Miąsko
12436cc6ada1STomasz Miąsko /// Computes A + B. When computation wraps around sets the error and returns
12446cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
addAssign(uint64_t & A,uint64_t B)12456cc6ada1STomasz Miąsko bool Demangler::addAssign(uint64_t &A, uint64_t B) {
12466cc6ada1STomasz Miąsko if (A > std::numeric_limits<uint64_t>::max() - B) {
12476cc6ada1STomasz Miąsko Error = true;
12486cc6ada1STomasz Miąsko return false;
12496cc6ada1STomasz Miąsko }
12506cc6ada1STomasz Miąsko
12516cc6ada1STomasz Miąsko A += B;
12526cc6ada1STomasz Miąsko return true;
12536cc6ada1STomasz Miąsko }
12546cc6ada1STomasz Miąsko
12556cc6ada1STomasz Miąsko /// Computes A * B. When computation wraps around sets the error and returns
12566cc6ada1STomasz Miąsko /// false. Otherwise assigns the result to A and returns true.
mulAssign(uint64_t & A,uint64_t B)12576cc6ada1STomasz Miąsko bool Demangler::mulAssign(uint64_t &A, uint64_t B) {
12586cc6ada1STomasz Miąsko if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) {
12596cc6ada1STomasz Miąsko Error = true;
12606cc6ada1STomasz Miąsko return false;
12616cc6ada1STomasz Miąsko }
12626cc6ada1STomasz Miąsko
12636cc6ada1STomasz Miąsko A *= B;
12646cc6ada1STomasz Miąsko return true;
12656cc6ada1STomasz Miąsko }
1266