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