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