1 /* 2 DMANGLE.D 3 --------- 4 Copyright (c) 2015-2016 eBay Software Foundation 5 Written by Andrew Trotman 6 Licensed under the 3-clause BSD license (see here:https://en.wikipedia.org/wiki/BSD_licenses) 7 8 The D runtime name demangle routine appears to be unable to demangle some names, such as those 9 that contain lambdas. This module is written as an exploration of D name demangling. 10 */ 11 module demangle; 12 import std.ascii; 13 import std.stdio; 14 import std.conv; 15 import std.format; 16 import std..string; 17 import std.array; 18 19 private const(char)* source; 20 private const(char)* end; 21 private size_t peek_operations; 22 private size_t max_allowable_peek_operations; 23 24 /* 25 GET_NEXT() 26 ---------- 27 */ 28 char get_next() 29 { 30 char ch = source < end ? *source++ : 0; 31 // writeln("{", ch, "}"); 32 return ch; 33 } 34 35 /* 36 PEEK_NEXT() 37 ----------- 38 */ 39 private char peek_next(size_t distance = 0) 40 { 41 if (peek_operations++ > max_allowable_peek_operations){ 42 throw new Exception("Infinate Loop (badly formed mangled name)"); 43 } 44 char ch = source + distance < end ? *(source + distance) : 0; 45 // writeln("[", ch, "]"); 46 return ch; 47 } 48 49 /* 50 NUMBER() 51 -------- 52 Number: 53 Digit 54 Digit Number 55 56 Digit: 57 0 58 1 59 2 60 3 61 4 62 5 63 6 64 7 65 8 66 9 67 */ 68 private size_t number(size_t max_digits = size_t.max) 69 { 70 size_t answer = 0; 71 72 while (isDigit(peek_next()) && max_digits-- > 0) 73 answer = answer * 10 + get_next() - '0'; 74 75 return answer; 76 } 77 78 /* 79 LNAME() 80 ------- 81 LName: 82 Number Name 83 */ 84 private const(char)[] LName(size_t max_digits) 85 { 86 const(char)[] name; 87 88 if (!isDigit(peek_next())) 89 return name; 90 91 foreach (current; 0 .. number(max_digits)) 92 { 93 if (peek_next() == 0) 94 throw new Exception("badly formed LName"); 95 name ~= get_next(); 96 } 97 98 return name; 99 } 100 /* 101 HEXDIGITS() 102 ----------- 103 HexDigits: 104 HexDigit 105 HexDigit HexDigits 106 107 HexDigit: 108 Digit 109 A 110 B 111 C 112 D 113 E 114 F 115 */ 116 private const(char)[] HexDigits() 117 { 118 const(char)[] answer; 119 120 while (true) switch (peek_next()) 121 { 122 case '0': .. case '9': 123 case 'A': .. case 'Z': 124 answer ~= get_next(); 125 break; 126 default: 127 return answer; 128 } 129 } 130 131 /* 132 EXPONENT() 133 ---------- 134 NOTE: An exponent must start with a 'P'. 135 Exponent: 136 N Number 137 Number 138 */ 139 private const(char)[] Exponent() 140 { 141 if (peek_next() != 'P') 142 return ""; 143 get_next(); 144 return to!string(number()); 145 } 146 147 /* 148 HEXFLOAT() 149 HexFloat: 150 NAN 151 INF 152 NINF 153 N HexDigits P Exponent 154 HexDigits P Exponent 155 156 Exponent: 157 N Number 158 Number 159 */ 160 private const(char)[] HexFloat() 161 { 162 const(char)[] answer; 163 164 switch (peek_next()) 165 { 166 case 'I': // INF 167 if (peek_next(1) == 'N' && peek_next(2) == 'F') 168 { 169 get_next(); 170 get_next(); 171 get_next(); 172 return "real.infinity"; 173 } 174 return answer; 175 case 'N': 176 switch (peek_next(1)) 177 { 178 case 'A': // NAN 179 if (peek_next(2) == 'N') 180 { 181 get_next(); 182 get_next(); 183 get_next(); 184 return "real.nan"; 185 } 186 /* 187 NAB: Negative 0xAB! This is a nasty case. 188 */ 189 auto hex = HexDigits(); 190 answer ~= '-' ~ "0x" ~ hex[0] ~ "." ~ hex[1 .. $] ~ Exponent(); 191 return answer; 192 case 'I': // NINF 193 if (peek_next(2) == 'N' && peek_next(3) == 'F') 194 { 195 get_next(); 196 get_next(); 197 get_next(); 198 get_next(); 199 return "-real.infinity"; 200 } 201 return answer; 202 case '0': .. case '9': // a negative number (That's what the N stands for) 203 case 'B': .. case 'F': 204 auto hex = HexDigits(); 205 answer ~= '-' ~ "0x" ~ hex[0] ~ "." ~ hex[1 .. $] ~ Exponent(); 206 return answer; 207 default: 208 return answer; 209 } 210 case '0': .. case '9': // a negative number (That's what the N stands for) 211 case 'A': .. case 'F': 212 auto hex = HexDigits(); 213 answer ~= '-' ~ "0x" ~ hex[0] ~ "." ~ hex[1 .. $] ~ Exponent(); 214 return answer; 215 default: 216 return answer; 217 } 218 } 219 220 /* 221 NYBBLE() 222 -------- 223 */ 224 private size_t nybble() 225 { 226 auto character = get_next(); 227 return character >= '0' 228 && character <= '9' ? character - '0' : character >= 'A' 229 && character <= 'F' ? character - 'A' + 10 : character >= 'a' 230 && character <= 'f' ? character - 'a' + 10 : 0; 231 } 232 233 /* 234 BYTE_HEX_NUMBER() 235 ----------------- 236 */ 237 private size_t byte_hex_number() 238 { 239 switch (peek_next()) 240 { 241 case '0': .. case '9': // a negative number (That's what the N stands for) 242 case 'A': .. case 'F': 243 case 'a': .. case 'f': 244 switch (peek_next(1)) 245 { 246 case '0': .. case '9': // a negative number (That's what the N stands for) 247 case 'A': .. case 'F': 248 case 'a': .. case 'f': 249 size_t n1 = nybble(); 250 size_t n2 = nybble(); 251 return (n1 << 4) | n2; 252 default: 253 return 0; 254 } 255 default: 256 return 0; 257 } 258 } 259 260 /* 261 TO_HEX() 262 -------- 263 */ 264 private const(char)[] to_hex(ulong number, size_t digits) 265 { 266 auto writer = appender!string(); 267 formattedWrite(writer, "%0*x", digits, number); 268 return writer.data; 269 } 270 271 /* 272 FORMAT_ANSWER() 273 --------------- 274 */ 275 private const(char)[] format_value(char sign, ulong value, char as) 276 { 277 switch (as) 278 { 279 case 'a', 'u', 'w': // (char, wchar, dchar) 280 switch (value) 281 { 282 case '\'': 283 return "'\\''"; 284 case '\\': 285 return "'\\\\'"; 286 case '\a': 287 return "'\\a'"; 288 case '\b': 289 return "'\\b'"; 290 case '\f': 291 return "'\\f'"; 292 case '\n': 293 return "'\\n'"; 294 case '\r': 295 return "'\\r'"; 296 case '\t': 297 return "'\\t'"; 298 case '\v': 299 return "'\\v'"; 300 default: 301 switch (as) 302 { 303 case 'a': 304 if (value >= ' ' && value < '~') 305 return "'" ~ cast(char) value ~ "'"; 306 return "\\x" ~ to_hex(value, 2); 307 case 'u': 308 return "'\\u" ~ to_hex(value, 4) ~ "'"; 309 case 'w': 310 return "'\\U" ~ to_hex(value, 8) ~ "'"; 311 default: 312 return to!string(value); 313 } 314 } 315 case 'b': // bool 316 return value ? "true" : "false"; 317 case 'h', 't', 'k': // ubyte, ushort, uint 318 return (sign ? "-" : "") ~ to!string(value) ~ "u"; 319 case 'l': // long 320 return (sign ? "-" : "") ~ to!string(value) ~ "L"; 321 case 'm': // ulong 322 return to!string(value) ~ "uL"; 323 default: 324 return to!string(value); 325 } 326 } 327 /* 328 VALUE() 329 ------- 330 Value: 331 n 332 Number 333 i Number 334 N Number 335 e HexFloat 336 c HexFloat c HexFloat 337 CharWidth Number _ HexDigits 338 A Number Value... 339 S Number Value... 340 341 CharWidth: 342 a 343 w 344 d 345 */ 346 private const(char)[] Value(const(char)[] name = null, char parent_type = '\0') 347 { 348 const(char)[] answer; 349 size_t length; 350 351 switch (peek_next()) 352 { 353 case 'n': 354 get_next(); 355 return "null"; 356 case 'i': 357 get_next(); 358 return format_value('+', number(), parent_type); 359 case 'N': 360 get_next(); //negative number 361 return format_value('-', number(), parent_type); 362 case '0': .. case '9': 363 return format_value('+', number(), parent_type); 364 case 'e': 365 get_next(); 366 return HexFloat(); 367 case 'c': 368 get_next(); 369 return HexFloat() ~ "+" ~ HexFloat() ~ "i"; 370 case 'S': 371 get_next(); 372 length = number(); 373 foreach (num; 0 .. length) 374 answer ~= (num == 0 ? "" : ", ") ~ Value(); 375 return name ~ "(" ~ answer ~ ")"; 376 case 'A': 377 get_next(); 378 length = number(); 379 380 if (parent_type == 'H') 381 foreach (num; 0 .. length) 382 answer ~= (num == 0 ? "" : ", ") ~ Value() ~ ":" ~ Value(); 383 else 384 foreach (num; 0 .. length) 385 answer ~= (num == 0 ? "" : ", ") ~ Value(); 386 return "[" ~ answer ~ "]"; 387 case 'a': // CharWidth 388 case 'w': 389 case 'd': 390 immutable sub_type = get_next(); 391 length = number(); 392 get_next(); // should be an '_' 393 answer ~= '"'; 394 foreach (num; 0 .. length) 395 { 396 auto got = byte_hex_number(); 397 if (got < ' ' || got > '~') 398 answer ~= "\\x" ~ to_hex(got, 2); 399 else 400 answer ~= to!char(got); 401 } 402 answer ~= '"'; 403 if (sub_type != 'a') 404 answer ~= sub_type; 405 return answer; 406 default: 407 return ""; 408 } 409 } 410 411 /* 412 TEMPLATEARGS() 413 -------------- 414 TemplateArgs: 415 TemplateArg 416 TemplateArg TemplateArgs 417 418 TemplateArg: 419 TemplateArgX 420 H TemplateArgX 421 422 TemplateArgX: 423 T Type 424 V Type Value 425 S LName 426 */ 427 private const(char)[] TemplateArgs() 428 { 429 size_t count = 0; 430 const(char)[] answer; 431 432 while (true) 433 { 434 switch (peek_next()) 435 { 436 case 'H': 437 get_next(); 438 break; 439 case 'T': 440 get_next(); 441 if (count++ != 0) 442 answer ~= ", "; 443 answer ~= Type(""); 444 break; 445 case 'V': 446 get_next(); 447 if (count++ != 0) 448 answer ~= ", "; 449 char t = peek_next(); // this is a thorny case where t == H means an associateive array. the example in the unittest is HiiA2i1i2i3i4 450 auto of = Type(""); 451 auto val = Value(of, t); 452 answer ~= val; 453 break; 454 case 'S': 455 get_next(); 456 if (count++ != 0) 457 answer ~= ", "; 458 answer ~= QualifiedName(); 459 break; 460 case 'Z': 461 get_next(); 462 return answer; 463 default: 464 return answer; 465 } 466 } 467 } 468 469 /* 470 QUALIFIEDNAME() 471 --------------- 472 QualifiedName: 473 SymbolName 474 SymbolName QualifiedName 475 476 SymbolName: 477 LName 478 TemplateInstanceName 479 */ 480 private const(char)[] QualifiedName() 481 { 482 const(char)[] name; 483 const(char)[] part; 484 size_t parts = 0; 485 size_t digits = 0; 486 487 /* 488 See D language Issue 3043 in Bugzilla (https://issues.dlang.org/show_bug.cgi?id=3043) which says: 489 490 For example, this code 491 -------------------- 492 module test; 493 struct Temp(alias a) {} 494 template sym() {} 495 pragma(msg, Temp!(sym).mangleof); 496 -------------------- 497 prints "4test20__T4TempS94test3symZ4Temp". 498 Here sym is mangled to "S94test3sym"; the Number is "9" and the Name is "4test3sym". But a demangler will recognize the Number and the Name as "94" and "test3sym", respectively. 499 */ 500 while (isDigit(peek_next())) 501 { 502 auto original_source = source; 503 auto original_end = end; 504 505 digits = 0; 506 while (isDigit(peek_next(digits))) 507 digits++; 508 509 while (true) 510 { 511 try 512 { 513 part = LName(digits); 514 if (part.length == 0) 515 break; 516 if (parts++ != 0) 517 name ~= '.'; 518 519 if (part.length >= 3 && part[0 .. 3] == "__T") 520 name ~= demangle_entry(part[3 .. $], true); // template so do a recursive call 521 else if (part.length > 2 && part[0 .. 2] == "_D") // oh really? This actually happens? 522 name ~= demangle_entry(part[2 .. $], false); 523 else if (isDigit(part[0])) // Issue 3043 524 name ~= demangle_entry(part, false); 525 else 526 name ~= part; 527 break; 528 } 529 catch (Throwable) 530 { 531 if (digits <= 1){ 532 throw new Exception("badly formed LName"); 533 } 534 source = original_source; 535 end = original_end; 536 name = ""; 537 parts = 0; 538 part = ""; 539 digits--; 540 } 541 } 542 } 543 return name; 544 } 545 546 /* 547 TYPEMODIFIERS() 548 --------------- 549 TypeModifiers 550 Const 551 Wild 552 Wild Const 553 Shared 554 Shared Const 555 Shared Wild 556 Shared Wild Const 557 Immutable 558 559 Shared: 560 O 561 562 Const: 563 x 564 565 Immutable: 566 y 567 568 Wild: 569 Ng 570 */ 571 private const(char)[] TypeModifiers() 572 { 573 const(char)[] modifiers; 574 575 size_t count = 0; 576 do 577 { 578 switch (peek_next()) 579 { 580 case 'x': 581 modifiers ~= (count != 0 ? " " : "") ~ "const"; 582 break; 583 case 'N': // "wild" 584 if (peek_next(1) == 'g') 585 { 586 modifiers ~= (count != 0 ? " " : "") ~ "inout"; 587 get_next(); 588 } 589 else 590 return modifiers; 591 break; 592 case 'O': 593 modifiers ~= (count != 0 ? " " : "") ~ "shared"; 594 break; 595 case 'y': 596 modifiers ~= (count != 0 ? " " : "") ~ "immutable"; 597 break; 598 default: 599 return modifiers; 600 } 601 get_next(); 602 count++; 603 } 604 while (true); 605 } 606 607 /* 608 CALLCONVENTION() 609 ---------------- 610 CallConvention: 611 F // D 612 U // C 613 W // Windows 614 V // Pascal 615 R // C++ 616 */ 617 private const(char)[] CallConvention() 618 { 619 switch (peek_next()) 620 { 621 case 'F': 622 get_next(); 623 return ""; 624 case 'U': 625 get_next(); 626 return "extern (C) "; 627 case 'W': 628 get_next(); 629 return "extern (Windows) "; 630 /* 631 case 'V': 632 get_next(); 633 return "extern (Pascal) "; 634 */ 635 case 'R': 636 get_next(); 637 return "extern (C++) "; 638 default: 639 return ""; 640 } 641 } 642 643 /* 644 IS_CALLCONVENTION() 645 ---------------- 646 */ 647 private bool is_CallConvention() 648 { 649 switch (peek_next()) 650 { 651 case 'F': 652 case 'U': 653 case 'W': 654 // case 'V': 655 case 'R': 656 return true; 657 default: 658 return false; 659 } 660 } 661 662 /* 663 FUNCATTRS() 664 ----------- 665 FuncAttrs: 666 FuncAttr 667 FuncAttr FuncAttrs 668 669 FuncAttr: 670 empty 671 FuncAttrPure 672 FuncAttrNothrow 673 FuncAttrProperty 674 FuncAttrRef 675 FuncAttrTrusted 676 FuncAttrSafe 677 FuncAttrNogc 678 679 FuncAttrPure: 680 Na 681 682 FuncAttrNothrow: 683 Nb 684 685 FuncAttrRef: 686 Nc 687 688 FuncAttrProperty: 689 Nd 690 691 FuncAttrTrusted: 692 Ne 693 694 FuncAttrSafe: 695 Nf 696 697 FuncAttrNogc: 698 Ni 699 */ 700 const(char)[] FuncAttrs() 701 { 702 const(char)[] answer; 703 704 while (true) 705 if (peek_next() == 'N') 706 { 707 switch (peek_next(1)) 708 { 709 case 'a': 710 answer ~= "pure "; 711 break; 712 case 'b': 713 answer ~= "nothrow "; 714 break; 715 case 'c': 716 answer ~= "ref "; 717 break; 718 case 'd': 719 answer ~= "@property "; 720 break; 721 case 'e': 722 answer ~= "@trusted "; 723 break; 724 case 'f': 725 answer ~= "@safe "; 726 break; 727 case 'i': 728 answer ~= "@nogc "; 729 break; 730 default: 731 return answer; 732 } 733 get_next(); 734 get_next(); 735 } 736 else 737 return answer; 738 } 739 740 /* 741 PARAMETERS() 742 ------------ 743 Parameters: 744 Parameter 745 Parameter Parameters 746 747 Parameter: 748 Parameter2 749 M Parameter2 // scope 750 751 Parameter2: 752 Type 753 J Type // out 754 K Type // ref 755 L Type // lazy 756 757 ParamClose 758 X // variadic T t...) style 759 Y // variadic T t,...) style 760 Z // not variadic 761 */ 762 const(char)[] Parameters() 763 { 764 size_t count = 0; 765 const(char)[] answer; 766 767 while (true) 768 { 769 switch (peek_next()) 770 { 771 case 'M': 772 get_next(); 773 if (count++ != 0) 774 { 775 answer ~= ", "; 776 } 777 answer ~= "scope " ~ Parameters(); 778 break; 779 case 'J': 780 get_next(); 781 if (count++ != 0) 782 { 783 answer ~= ", "; 784 } 785 answer ~= "out " ~ Type("", true); 786 break; 787 case 'K': 788 get_next(); 789 if (count++ != 0) 790 { 791 answer ~= ", "; 792 } 793 answer ~= "ref " ~ Type("", true); 794 break; 795 case 'L': 796 get_next(); 797 if (count++ != 0) 798 { 799 answer ~= ", "; 800 } 801 answer ~= "lazy " ~ Type("", true); 802 break; 803 case 'X': 804 get_next(); 805 count++; 806 answer ~= "..."; 807 return answer; 808 case 'Y': 809 get_next(); 810 answer ~= ", ..."; 811 return answer; 812 case 'Z': 813 get_next(); 814 return answer; 815 case '0': .. case '9': 816 answer ~= QualifiedName(); 817 break; 818 case 0: 819 return answer; 820 default: 821 if (count++ != 0) 822 { 823 answer ~= ", "; 824 } 825 answer ~= Type("", true); 826 break; 827 } 828 } 829 } 830 831 /* 832 TYPEFUNCTION() 833 -------------- 834 TypeFunction: 835 CallConvention FuncAttrs Parameters ParamClose Type 836 */ 837 private const(char)[] TypeFunction(const(char)[] name, bool is_deligate = false, bool in_struct = false) 838 { 839 auto convention = CallConvention(); 840 auto func_attrs = FuncAttrs(); 841 auto params = Parameters(); 842 auto the_type = Type("", true, true); 843 844 if (!in_struct) 845 return convention ~ func_attrs ~ the_type ~ (the_type.length == 0 ? "" : " ") ~ name ~ ( 846 is_deligate ? "delegate" : "") ~ "(" ~ params ~ ")"; 847 else 848 return name ~ "(" ~ params ~ ")"; 849 } 850 851 /* 852 TYPEX() 853 ------- 854 TypeX: 855 TypeArray 856 TypeStaticArray 857 TypeAssocArray 858 TypePointer 859 TypeFunction 860 TypeIdent 861 TypeClass 862 TypeStruct 863 TypeEnum 864 TypeTypedef 865 TypeDelegate 866 TypeVoid 867 TypeByte 868 TypeUbyte 869 TypeShort 870 TypeUshort 871 TypeInt 872 TypeUint 873 TypeLong 874 TypeUlong 875 TypeFloat 876 TypeDouble 877 TypeReal 878 TypeIfloat 879 TypeIdouble 880 TypeIreal 881 TypeCfloat 882 TypeCdouble 883 TypeCreal 884 TypeBool 885 TypeChar 886 TypeWchar 887 TypeDchar 888 TypeNull 889 [*] TypeTuple /// THESE DON'T APPEAR TO EXIST SO THEY ARE UNIMPLEMENTED 890 TypeVector 891 Internal 892 893 TypeArray: 894 A Type 895 896 TypeStaticArray: 897 G Number Type 898 899 TypeAssocArray: 900 H Type Type 901 902 TypePointer: 903 P Type 904 905 TypeVector: 906 Nh Type 907 908 TypeIdent: 909 I QualifiedName 910 911 TypeClass: 912 C QualifiedName 913 914 TypeStruct: 915 S QualifiedName 916 917 TypeEnum: 918 E QualifiedName 919 920 TypeTypedef: 921 T QualifiedName 922 923 TypeDelegate: 924 D TypeModifiers TypeFunction 925 D TypeFunction 926 927 TypeVoid: 928 v 929 930 TypeByte: 931 g 932 933 TypeUbyte: 934 h 935 936 TypeShort: 937 s 938 939 TypeUshort: 940 t 941 942 TypeInt: 943 i 944 945 TypeUint: 946 k 947 948 TypeLong: 949 l 950 951 TypeUlong: 952 m 953 954 TypeFloat: 955 f 956 957 TypeDouble: 958 d 959 960 TypeReal: 961 e 962 963 TypeIfloat: 964 o 965 966 TypeIdouble: 967 p 968 969 TypeIreal: 970 j 971 972 TypeCfloat: 973 q 974 975 TypeCdouble: 976 r 977 978 TypeCreal: 979 c 980 981 TypeBool: 982 b 983 984 TypeChar: 985 a 986 987 TypeWchar: 988 u 989 990 TypeDchar: 991 w 992 993 TypeNull: 994 n 995 996 Internal: 997 Z 998 */ 999 private const(char)[] TypeX(const(char)[] name = "", bool allow_deligates = false, bool in_struct = false) 1000 { 1001 static immutable string[23] primitives = [ 1002 "char", // a 1003 "bool", // b 1004 "creal", // c 1005 "double", // d 1006 "real", // e 1007 "float", // f 1008 "byte", // g 1009 "ubyte", // h 1010 "int", // i 1011 "ireal", // j 1012 "uint", // k 1013 "long", // l 1014 "ulong", // m 1015 "null", // n 1016 "ifloat", // o 1017 "idouble", // p 1018 "cfloat", // q 1019 "cdouble", // r 1020 "short", // s 1021 "ushort", // t 1022 "wchar", // u 1023 "void", // v 1024 "dchar", // w 1025 ]; 1026 1027 switch (peek_next()) 1028 { 1029 case 'a': .. case 'w': // base types 1030 return primitives[get_next() - 'a'] ~ (name.length == 0 ? "" : (" " ~ name)); 1031 case 'A': // TypeArray 1032 get_next(); 1033 return Type("") ~ "[]" ~ (name.length == 0 ? "" : (" " ~ name)); 1034 case 'F': // CallConvention 1035 case 'U': 1036 case 'W': 1037 case 'V': 1038 case 'R': 1039 get_next(); 1040 return TypeFunction(name, false, in_struct); 1041 case 'G': // TypeStaticArray: 1042 get_next(); 1043 auto count = number(); 1044 auto of = Type(""); 1045 return of ~ "[" ~ to!string(count) ~ "]" ~ (name.length == 0 ? "" : (" " ~ name)); 1046 case 'H': // TypeAssocArray 1047 get_next(); 1048 auto type1 = Type(""); 1049 auto type2 = Type(""); 1050 return type1 ~ "[" ~ type2 ~ "]" ~ (name.length == 0 ? "" : (" " ~ name)); 1051 case 'P': // TypePointer 1052 get_next(); 1053 auto of = Type(""); 1054 return of ~ "*" ~ (name.length == 0 ? "" : (" " ~ name)); 1055 case 'N': 1056 switch (peek_next(1)) 1057 { 1058 case 'h': // TypeVector 1059 get_next(); 1060 get_next(); 1061 return "__vector(" ~ Type("") ~ ")" ~ (name.length == 0 ? "" : (" " ~ name)); 1062 default: 1063 throw new Exception("Uknown type N" ~ peek_next(1)); 1064 } 1065 case 'I': // TypeIdent 1066 case 'C': // TypeClass 1067 case 'S': // TypeStruct 1068 case 'E': // TypeEnum 1069 case 'T': // TypeTypedef 1070 get_next(); 1071 const(char)[] answer = QualifiedName() ~ (name.length == 0 ? "" : (" " ~ name)); 1072 if (is_CallConvention()) 1073 answer = Type(answer, false, false, true); 1074 while (isDigit(peek_next())) 1075 answer ~= "." ~ QualifiedName(); 1076 return answer; 1077 case 'D': // TypeDelegate 1078 get_next(); 1079 auto modifiers = TypeModifiers(); 1080 auto func = TypeFunction(name, allow_deligates); 1081 if (modifiers.length != 0){ 1082 return modifiers ~ " " ~ func; 1083 } 1084 else { 1085 return func; 1086 } 1087 case 'z': 1088 switch (peek_next(1)) 1089 { 1090 case 'k': 1091 get_next(); 1092 get_next(); 1093 return "ucent"; 1094 case 'i': 1095 get_next(); 1096 get_next(); 1097 return "cent"; 1098 default: 1099 return "unknown"; 1100 } 1101 case 'Z': // Internal (documented to exist but it is undocumented what it is) 1102 return name; 1103 default: 1104 return name; 1105 } 1106 } 1107 1108 /* 1109 TYPE() 1110 ------ 1111 Type: 1112 TypeModifiers TypeX 1113 TypeX 1114 */ 1115 private const(char)[] Type(const(char)[] name, bool allow_deligates = false, 1116 bool is_function = false, bool in_struct = false) 1117 { 1118 const(char)[] answer; 1119 1120 auto mod = TypeModifiers(); 1121 1122 if (mod.length != 0) 1123 { 1124 if (is_function) 1125 answer ~= mod ~ " "; 1126 else 1127 answer ~= mod ~ "("; 1128 } 1129 1130 answer ~= TypeX(name, allow_deligates, in_struct); 1131 1132 if (mod.length != 0) 1133 { 1134 if (is_function) 1135 answer ~= ""; 1136 else 1137 answer ~= ")"; 1138 } 1139 1140 return answer; 1141 } 1142 1143 /* 1144 DECODE() 1145 -------- 1146 */ 1147 private const(char)[] decode(bool is_template = false) 1148 { 1149 const(char)[] name; 1150 1151 name ~= QualifiedName(); 1152 if (name.length == 0) 1153 return ""; 1154 1155 if (peek_next() == 'M') 1156 get_next(); // discard the 'M' 1157 1158 if (is_template) 1159 name ~= "!(" ~ TemplateArgs(); 1160 else 1161 name = Type(name, false, true); 1162 1163 while (isDigit(peek_next())) 1164 { 1165 name ~= "." ~ QualifiedName(); 1166 1167 if (peek_next() == 'M') 1168 get_next(); // discard the 'M' 1169 1170 name = Type(name); 1171 } 1172 1173 if (is_template) 1174 name ~= ")"; 1175 1176 return name; 1177 } 1178 1179 /* 1180 DEMANGLE_ENTRY() 1181 ---------------- 1182 recursive entry into the demangleing code. 1183 */ 1184 const(char)[] demangle_entry(const(char)[] mangled, bool is_template = false) 1185 { 1186 const(char)[] answer; 1187 auto stack_source = source; 1188 auto stack_end = end; 1189 1190 source = mangled.ptr; 1191 end = source + mangled.length; 1192 answer = decode(is_template); 1193 source = stack_source; 1194 end = stack_end; 1195 1196 return answer; 1197 } 1198 1199 /* 1200 DEMANGLE() 1201 ---------- 1202 _D QualifiedName Type 1203 _D QualifiedName M Type 1204 */ 1205 const(char)[] demangle(const(char)[] mangled, char[] destination = null) 1206 { 1207 if (mangled.length < 3) 1208 return mangled; 1209 if (mangled[0 .. 2] != "_D") 1210 return mangled; 1211 1212 /* 1213 Yup, main in not mangled in D so we have a special case checking for it here. 1214 */ 1215 if (mangled == "_Dmain") 1216 return "int main(string[] args)"; 1217 1218 /* 1219 We don't want any infinate loops so prevent them here. 1220 */ 1221 peek_operations = 0; 1222 max_allowable_peek_operations = mangled.length * 10; 1223 1224 try 1225 { 1226 auto got = demangle_entry(mangled[2 .. $]); 1227 return got.length == 0 ? mangled : got; 1228 } 1229 catch (Throwable) 1230 { 1231 return mangled; 1232 } 1233 } 1234 1235 /* 1236 UNITTEST 1237 -------- 1238 */ 1239 unittest 1240 { 1241 foreach(current, name; table) 1242 { 1243 if (current >= 0) 1244 { 1245 auto got = demangle(name[0]); 1246 if (got != name[1]) 1247 { 1248 writeln(" test:", current, " FAILED"); 1249 writeln(" Source:", name[0]); 1250 writeln("nexpected:", name[1]); 1251 writeln(" got:", got, "\n"); 1252 return; 1253 } 1254 } 1255 } 1256 1257 writeln("Passed demangle() unittest."); 1258 } 1259 1260 immutable string[2][] table = 1261 [ 1262 /* 1263 These are nasty cases that came from the D bugzilla archive 1264 */ 1265 ["_D4test20__T4TempS94test3symZ4Temp", "test.Temp!(test.sym).Temp"], // CORRECT: contains recursive length (see the 94) 1266 ["_D1a3funPFZv", "void ()* a.fun"], // UNKNOWN: pointer to function 1267 ["_D8demangle32__T4testTS8demangle3fooVnnZ3barZ3bazFZv", "void demangle.test!(demangle.foo, null.bar).baz()"], // WRONG: ambiguity as 'V' is both the Pascal call convention and template parameter marker (Issue 14591) 1268 ["_D8demangle27__T4testTS8demangle3fooVnnZ3bar3bazFZv_D1a5Class1cMxFZv", "void demangle.test!(demangle.foo, null).bar.baz()"], // CORRECT: ambiguity as 'V' is both the Pascal call convention and template parameter marker (Issue 14591) 1269 ["_D1a5Class1wMNgFZv", "inout void a.Class.w()"], // CORRECT: inout return value 1270 ["_D16TypeInfo_HAyayAa6__initZ", "TypeInfo_HAyayAa.__init"], // CORRECT: the mangler appears to be incorrect in this case (Issue 11586) 1271 ["_D4util13demangle_funs1A18さいごの果実MFiZv", "void util.demangle_funs.A.さいごの果実(int)"], // CORRECT: unicode in mangled name (Issue 10393) 1272 ["_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv", "void demangle.fn!([1:2, 3:4]).fn()"], // CORRECT: associative array (Issue 6526) 1273 ["_D8demangle1S2fnMFZv", "void demangle.S.fn()"], // CORRECT: function type modifiers 1274 ["_D8demangle1S2fnMxFZv", "const void demangle.S.fn()"], // CORRECT: function type modifiers 1275 ["_D8demangle1S2fnMyFZv", "immutable void demangle.S.fn()"], // CORRECT: function type modifiers 1276 ["_D8demangle1S2fnMNgFZv", "inout void demangle.S.fn()"], // CORRECT: function type modifiers 1277 ["_D8demangle1S2fnMOFZv", "shared void demangle.S.fn()"], // CORRECT: function type modifiers 1278 ["_D8demangle1S2fnMOxFZv", "shared const void demangle.S.fn()"], // CORRECT: function type modifiers 1279 ["_D8demangle1S2fnMONgFZv", "shared inout void demangle.S.fn()"], // CORRECT: function type modifiers 1280 ["_D8demangle1S2fnMONgxFZv", "shared inout const void demangle.S.fn()"], // CORRECT: function type modifiers 1281 ["_D8serenity9persister6Sqlite7__arrayZ", "serenity.persister.Sqlite.__array"], // CORRECT: non-functions 1282 ["_D10TypeInfo_C6__vtblZ", "TypeInfo_C.__vtbl"], // CORRECT: C++ vtbl (virtual function tables) 1283 ["_D2rt3aaA12__ModuleInfoZ", "rt.aaA.__ModuleInfo"], // CORRECT: Module 1284 1285 // CORRECT: dots in return types 1286 ["_D3dmd6Parser6Parser15parsePrimaryExpMFZC3dmd10Expression10Expression", "dmd.Expression.Expression dmd.Parser.Parser.parsePrimaryExp()"], 1287 1288 // CORRECT: function local symbols (Issue 6045) 1289 ["_D8serenity9persister6Sqlite70__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZv4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZv4Test", "serenity.persister.Sqlite.__unittest6().Test serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)"], 1290 1291 // UNKNOWN: 1292 ["_D3std11parallelism8TaskPool28__T6reduceVAyaa5_61202b2062Z130__T6reduceTS4test4mainFZv39__T3mapS28_D4test4mainFZv7getTermMFiZeZ49__T3mapTS3std5range15__T4iotaTyiTyiZ4iota6ResultZ3mapM6ResultZ6reduceMFS4test4mainFZv39__T3mapS28_D4test4mainFZv7getTermMFiZeZ49__T3mapTS3std5range15__T4iotaTyiTyiZ4iota6ResultZ3mapMFS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZS3std5range15__T4iotaTyiTyiZ4iota6Result6ResultZS4test4mainFZv39__T3mapS28_D4test4mainFZv7getTermMFiZeZ49__T3mapTS3std5range15__T4iotaTyiTyiZ4iota6ResultZ3mapM6Result6ResultZe", "std.parallelism.TaskPool.reduce!(\"a + b\").reduce!(test.main().map!(real void test.main().getTerm(int)).map!(std.range.iota!(immutable(int), immutable(int)).iota.Result).map).reduce(test.main().map!(real void test.main().getTerm(int)).map!(std.range.iota!(immutable(int), immutable(int)).iota.Result).map, scope test.main().map!(real void test.main().getTerm(int)).map!(std.range.iota!(immutable(int), immutable(int)).iota.Result).map (std.range.iota!(immutable(int), immutable(int)).iota(immutable(int), immutable(int))), scope Result.Result, real)"], 1293 1294 // WRONG: ambiguity in token length (see the 213). Issue 14576 1295 ["_D3std11parallelism8TaskPool28__T6reduceVAyaa5_61202b2062Z130__T6reduceTS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZ6ResultZ9MapResultZ6reduceMFS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZ6ResultZ9MapResultZ7useTaskMFNbNiNfKS3std11parallelism281__T4TaskS213std11parallelism3runTDFS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZ6ResultZ9MapResultmmZeTS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZ6ResultZ9MapResultTmTmZ4TaskZv", "nothrow @nogc @safe void std.parallelism.TaskPool.reduce!(\"a + b\").reduce!(std.algorithm.MapResult!(real test.main().getTerm(int), std.range.iota!(immutable(int), immutable(int)).iota(immutable(int), immutable(int)).Result).MapResult).reduce(std.algorithm.MapResult!(real test.main().getTerm(int), std.range.iota!(immutable(int), immutable(int)).iota(immutable(int), immutable(int)).Result).MapResult).useTask(ref std.parallelism.Task!(std11parallelism3runTDFS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5range15__T4iotaTyiTyiZ4iotaFyiyiZ6ResultZ9MapResultmmZeTS3std9algorithm91__T9MapResultS27_D4test4mainFZ7getTermMFiZeTS3std5).Task)"], 1296 1297 /* 1298 This is an attempt to get the mangler to generate a tuple token (which it does not) 1299 */ 1300 ["_D4test6point1S3std8typecons32__T5TupleTiVAyaa1_78TiVAyaa1_79Z5Tuple", "std.typecons.Tuple!(int, \"x\", int, \"y\").Tuple test.point1"], 1301 1302 /* 1303 These came from profiling this app. There are three that don't agree with the D runtime demangle (coz it failes). These are assumed to 1304 be correct here because the output here is believable. 1305 */ 1306 ["_D11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree22__T12find_and_addVbi1Z12find_and_addMFNbNcNiNfKC11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree4nodeKxAaZS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings", "nothrow ref @nogc @safe indexing_postings.indexing_postings!(7).indexing_postings binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.find_and_add!(true).find_and_add(ref binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.node, ref const(char[]))"], 1307 ["_D11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree4node6__ctorMFNbNiKxAaC9allocator9allocatorZC11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree4node", "nothrow @nogc binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.node binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.node.__ctor(ref const(char[]), allocator.allocator)"], 1308 ["_D11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree6__ctorMFNbNiNfC9allocator9allocatorZC11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree", "nothrow @nogc @safe binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.__ctor(allocator.allocator)"], 1309 ["_D11binary_tree118__T11binary_treeTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsZ11binary_tree7opIndexMFNcKxAaZS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings", "ref indexing_postings.indexing_postings!(7).indexing_postings binary_tree.binary_tree!(char[], indexing_postings.indexing_postings!(7).indexing_postings).binary_tree.opIndex(ref const(char[]))"], 1310 ["_D11hash_random26__T11hash_randomVii24TAxaZ11hash_randomFNaNbNiNfxAaZm", "pure nothrow @nogc @safe ulong hash_random.hash_random!(24, const(char)[]).hash_random(const(char[]))"], 1311 ["_D13instream_file13instream_file4readMFAaZm", "ulong instream_file.instream_file.read(char[])"], 1312 ["_D13instream_file13instream_file6__ctorMFAyaZC13instream_file13instream_file", "instream_file.instream_file instream_file.instream_file.__ctor(immutable(char)[])"], 1313 ["_D15stream_growable23__T15stream_growableTgZ15stream_growable5piece6__ctorMFNbNcNiNfC9allocator9allocatormZS15stream_growable23__T15stream_growableTgZ15stream_growable5piece", "nothrow ref @nogc @safe stream_growable.stream_growable!(byte).stream_growable.piece stream_growable.stream_growable!(byte).stream_growable.piece.__ctor(allocator.allocator, ulong)"], 1314 ["_D15stream_growable23__T15stream_growableTgZ15stream_growable6__ctorMFNbNiNfKC9allocator9allocatormdZC15stream_growable23__T15stream_growableTgZ15stream_growable", "nothrow @nogc @safe stream_growable.stream_growable!(byte).stream_growable stream_growable.stream_growable!(byte).stream_growable.__ctor(ref allocator.allocator, ulong, double)"], 1315 ["_D15stream_growable23__T15stream_growableTgZ15stream_growable9space_forMFNiNemZPg", "@nogc @trusted byte* stream_growable.stream_growable!(byte).stream_growable.space_for(ulong)"], 1316 ["_D15stream_growable23__T15stream_growableTtZ15stream_growable16replace_ultimateMFNaNbNiNftZv", "pure nothrow @nogc @safe void stream_growable.stream_growable!(ushort).stream_growable.replace_ultimate(ushort)"], 1317 ["_D15stream_growable23__T15stream_growableTtZ15stream_growable5piece6__ctorMFNbNcNiNfC9allocator9allocatormZS15stream_growable23__T15stream_growableTtZ15stream_growable5piece", "nothrow ref @nogc @safe stream_growable.stream_growable!(ushort).stream_growable.piece stream_growable.stream_growable!(ushort).stream_growable.piece.__ctor(allocator.allocator, ulong)"], 1318 ["_D15stream_growable23__T15stream_growableTtZ15stream_growable6__ctorMFNbNiNfKC9allocator9allocatormdZC15stream_growable23__T15stream_growableTtZ15stream_growable", "nothrow @nogc @safe stream_growable.stream_growable!(ushort).stream_growable stream_growable.stream_growable!(ushort).stream_growable.__ctor(ref allocator.allocator, ulong, double)"], 1319 ["_D15stream_growable23__T15stream_growableTtZ15stream_growable8ultimateMFNaNbNiNfZt", "pure nothrow @nogc @safe ushort stream_growable.stream_growable!(ushort).stream_growable.ultimate()"], 1320 ["_D15stream_growable23__T15stream_growableTtZ15stream_growable9space_forMFNiNemZPt", "@nogc @trusted ushort* stream_growable.stream_growable!(ushort).stream_growable.space_for(ulong)"], 1321 ["_D17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings3addMFNiNfmmZv", "@nogc @safe void indexing_postings.indexing_postings!(7).indexing_postings.add(ulong, ulong)"], 1322 ["_D17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings6__ctorMFNbNcNiNfC9allocator9allocatorZS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings", "nothrow ref @nogc @safe indexing_postings.indexing_postings!(7).indexing_postings indexing_postings.indexing_postings!(7).indexing_postings.__ctor(allocator.allocator)"], 1323 ["_D23directory_iterator_line23directory_iterator_line10set_sourceMFC8instream8instreamZv", "void directory_iterator_line.directory_iterator_line.set_source(instream.instream)"], 1324 ["_D23directory_iterator_line23directory_iterator_line8get_fileMFZAa", "char[] directory_iterator_line.directory_iterator_line.get_file()"], 1325 ["_D28compress_variable_byte_atire20__T12bytes_neededTmZ12bytes_neededFNaNbNiNfmZm", "pure nothrow @nogc @safe ulong compress_variable_byte_atire.bytes_needed!(ulong).bytes_needed(ulong)"], 1326 ["_D28compress_variable_byte_atire21__T13compress_intoTmZ13compress_intoFNaNbNiNePgmmZm", "pure nothrow @nogc @trusted ulong compress_variable_byte_atire.compress_into!(ulong).compress_into(byte*, ulong, ulong)"], 1327 ["_D3std4conv55__T11toTextRangeTmTS3std5stdio4File17LockingTextWriterZ11toTextRangeFNfmS3std5stdio4File17LockingTextWriterZv", "@safe void std.conv.toTextRange!(ulong, std.stdio.File.LockingTextWriter).toTextRange(ulong, std.stdio.File.LockingTextWriter)"], 1328 ["_D3std4conv91__T18emplaceInitializerTS15stream_growable23__T15stream_growableTgZ15stream_growable5pieceZ18emplaceInitializerFNaNbNcNiNeKS15stream_growable23__T15stream_growableTgZ15stream_growable5pieceZS15stream_growable23__T15stream_growableTgZ15stream_growable5piece", "pure nothrow ref @nogc @trusted stream_growable.stream_growable!(byte).stream_growable.piece std.conv.emplaceInitializer!(stream_growable.stream_growable!(byte).stream_growable.piece).emplaceInitializer(ref stream_growable.stream_growable!(byte).stream_growable.piece)"], 1329 ["_D3std4conv91__T18emplaceInitializerTS15stream_growable23__T15stream_growableTtZ15stream_growable5pieceZ18emplaceInitializerFNaNbNcNiNeKS15stream_growable23__T15stream_growableTtZ15stream_growable5pieceZS15stream_growable23__T15stream_growableTtZ15stream_growable5piece", "pure nothrow ref @nogc @trusted stream_growable.stream_growable!(ushort).stream_growable.piece std.conv.emplaceInitializer!(stream_growable.stream_growable!(ushort).stream_growable.piece).emplaceInitializer(ref stream_growable.stream_growable!(ushort).stream_growable.piece)"], 1330 ["_D3std5array102__T5arrayTS3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6ResultZ5arrayFNaNbNfS3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6ResultZAAya", "pure nothrow @safe immutable(char)[][] std.array.array!(std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result).array(std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result)"], 1331 ["_D3std5array18__T8AppenderTAAyaZ8Appender12__T3putTAyaZ3putMFAyaZ9__lambda2MFNaNbNiNeZAAya", "pure nothrow @nogc @trusted immutable(char)[][] std.array.Appender!(immutable(char)[][]).Appender.put!(immutable(char)[]).put(immutable(char)[]).__lambda2()"], 1332 ["_D3std5array18__T8AppenderTAAyaZ8Appender12__T3putTAyaZ3putMFNaNbNfAyaZv", "pure nothrow @safe void std.array.Appender!(immutable(char)[][]).Appender.put!(immutable(char)[]).put(immutable(char)[])"], 1333 ["_D3std5array18__T8AppenderTAAyaZ8Appender13ensureAddableMFNaNbNemZv", "pure nothrow @trusted void std.array.Appender!(immutable(char)[][]).Appender.ensureAddable(ulong)"], 1334 ["_D3std5array18__T8AppenderTAAyaZ8Appender6__ctorMFNaNbNcNeAAyaZS3std5array18__T8AppenderTAAyaZ8Appender", "pure nothrow ref @trusted std.array.Appender!(immutable(char)[][]).Appender std.array.Appender!(immutable(char)[][]).Appender.__ctor(immutable(char)[][])"], 1335 ["_D3std5array30__T19appenderNewCapacityVmi16Z19appenderNewCapacityFNaNbNiNfmmZm", "pure nothrow @nogc @safe ulong std.array.appenderNewCapacity!(16uL).appenderNewCapacity(ulong, ulong)"], 1336 ["_D3std5stdio20__T7writelnTAyaTAyaZ7writelnFNfAyaAyaZv", "@safe void std.stdio.writeln!(immutable(char)[], immutable(char)[]).writeln(immutable(char)[], immutable(char)[])"], 1337 ["_D3std5stdio24__T7writelnTAyaTmTAyaTmZ7writelnFNfAyamAyamZv", "@safe void std.stdio.writeln!(immutable(char)[], ulong, immutable(char)[], ulong).writeln(immutable(char)[], ulong, immutable(char)[], ulong)"], 1338 ["_D3std5stdio4File17LockingTextWriter10__T3putTaZ3putMFNbNiNfaZv", "nothrow @nogc @safe void std.stdio.File.LockingTextWriter.put!(char).put(char)"], 1339 ["_D3std5stdio4File17LockingTextWriter11__T3putTAaZ3putMFNfAaZv", "@safe void std.stdio.File.LockingTextWriter.put!(char[]).put(char[])"], 1340 ["_D3std5stdio4File17LockingTextWriter12__T3putTAyaZ3putMFNfAyaZv", "@safe void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[])"], 1341 ["_D3std5stdio4File20__T5writeTAyaTAyaTaZ5writeMFNfAyaAyaaZv", "@safe void std.stdio.File.write!(immutable(char)[], immutable(char)[], char).write(immutable(char)[], immutable(char)[], char)"], 1342 ["_D3std5stdio4File24__T5writeTAyaTmTAyaTmTaZ5writeMFNfAyamAyamaZv", "@safe void std.stdio.File.write!(immutable(char)[], ulong, immutable(char)[], ulong, char).write(immutable(char)[], ulong, immutable(char)[], ulong, char)"], 1343 ["_D3std6getopt16__T10getoptImplZ10getoptImplFNfKAAyaKS3std6getopt13configurationKS3std6getopt12GetoptResultZv", "@safe void std.getopt.getoptImpl!().getoptImpl(ref immutable(char)[][], ref std.getopt.configuration, ref std.getopt.GetoptResult)"], 1344 ["_D3std6getopt21__T12handleOptionTPbZ12handleOptionFAyaPbKAAyaKS3std6getopt13configurationbZb", "bool std.getopt.handleOption!(bool*).handleOption(immutable(char)[], bool*, ref immutable(char)[][], ref std.getopt.configuration, bool)"], 1345 ["_D3std6getopt23__T12handleOptionTPAyaZ12handleOptionFAyaPAyaKAAyaKS3std6getopt13configurationbZb", "bool std.getopt.handleOption!(immutable(char)[]*).handleOption(immutable(char)[], immutable(char)[]*, ref immutable(char)[][], ref std.getopt.configuration, bool)"], 1346 ["_D3std6getopt40__T10getoptImplTAyaTAyaTPAyaTAyaTAyaTPbZ10getoptImplFKAAyaKS3std6getopt13configurationKS3std6getopt12GetoptResultAyaAyaPAyaAyaAyaPbZv", "void std.getopt.getoptImpl!(immutable(char)[], immutable(char)[], immutable(char)[]*, immutable(char)[], immutable(char)[], bool*).getoptImpl(ref immutable(char)[][], ref std.getopt.configuration, ref std.getopt.GetoptResult, immutable(char)[], immutable(char)[], immutable(char)[]*, immutable(char)[], immutable(char)[], bool*)"], 1347 ["_D3std6getopt55__T6getoptTE3std6getopt6configTAyaTAyaTPAyaTAyaTAyaTPbZ6getoptFKAAyaE3std6getopt6configAyaAyaPAyaAyaAyaPbZS3std6getopt12GetoptResult", "std.getopt.GetoptResult std.getopt.getopt!(std.getopt.config, immutable(char)[], immutable(char)[], immutable(char)[]*, immutable(char)[], immutable(char)[], bool*).getopt(ref immutable(char)[][], std.getopt.config, immutable(char)[], immutable(char)[], immutable(char)[]*, immutable(char)[], immutable(char)[], bool*)"], 1348 ["_D3std9algorithm10comparison32__T3cmpVAyaa5_61203c2062TAaTAxaZ3cmpFAaAxaZ9__lambda6MFNaNbNiNeZi", "pure nothrow @nogc @trusted int std.algorithm.comparison.cmp!(\"a < b\", char[], const(char)[]).cmp(char[], const(char)[]).__lambda6()"], 1349 ["_D3std9algorithm10comparison32__T3cmpVAyaa5_61203c2062TAaTAxaZ3cmpFNaNbNiNfAaAxaZi", "pure nothrow @nogc @safe int std.algorithm.comparison.cmp!(\"a < b\", char[], const(char)[]).cmp(char[], const(char)[])"], 1350 ["_D3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6Result17ensureFrontLengthMFNaNbNiNfZv", "pure nothrow @nogc @safe void std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result.ensureFrontLength()"], 1351 ["_D3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6Result6__ctorMFNaNbNcNiNfAyaAyaZS3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6Result", "pure nothrow ref @nogc @safe std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result.__ctor(immutable(char)[], immutable(char)[])"], 1352 ["_D3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6Result8popFrontMFNaNbNiNfZv", "pure nothrow @nogc @safe void std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result.popFront()"], 1353 ["_D3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFNaNbNiNfAyaAyaZS3std9algorithm9iteration40__T8splitterVAyaa6_61203d3d2062TAyaTAyaZ8splitterFAyaAyaZ6Result", "pure nothrow @nogc @safe std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[]).Result std.algorithm.iteration.splitter!(\"a == b\", immutable(char)[], immutable(char)[]).splitter(immutable(char)[], immutable(char)[])"], 1354 ["_D3std9algorithm9searching34__T4findVAyaa6_61203d3d2062TAhTAhZ4findFNaNbNiNfAhAhZAh", "pure nothrow @nogc @safe ubyte[] std.algorithm.searching.find!(\"a == b\", ubyte[], ubyte[]).find(ubyte[], ubyte[])"], 1355 ["_D3std9algorithm9searching36__T4findVAyaa6_61203d3d2062TAyaTAyaZ4findFNaNbNiNfAyaAyaZAya", "pure nothrow @nogc @safe immutable(char)[] std.algorithm.searching.find!(\"a == b\", immutable(char)[], immutable(char)[]).find(immutable(char)[], immutable(char)[])"], 1356 ["_D3std9algorithm9searching41__T10startsWithVAyaa6_61203d3d2062TAhTAhZ10startsWithFNaNbNiNfAhAhZb", "pure nothrow @nogc @safe bool std.algorithm.searching.startsWith!(\"a == b\", ubyte[], ubyte[]).startsWith(ubyte[], ubyte[])"], 1357 ["_D3std9exception27__T7enforceHTC9ExceptionTbZ7enforceFNaNfbLAxaAyamZb", "pure @safe bool std.exception.enforce!(Exception, bool).enforce(bool, lazy const(char)[], immutable(char)[], ulong)"], 1358 ["_D3std9exception27__T7enforceHTC9ExceptionTmZ7enforceFNaNfmLAxaAyamZm", "pure @safe ulong std.exception.enforce!(Exception, ulong).enforce(ulong, lazy const(char)[], immutable(char)[], ulong)"], 1359 ["_D3str9toStringzFAaAyaZb", "bool str.toStringz(char[], immutable(char)[])"], 1360 ["_D4file4file4openMFAyaAyaZb", "bool file.file.open(immutable(char)[], immutable(char)[])"], 1361 ["_D4file4file4readMFAvZAv", "void[] file.file.read(void[])"], 1362 ["_D4hash115__T4hashTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsVii24Z4hash6__ctorMFNbNiC9allocator9allocatorZC4hash115__T4hashTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsVii24Z4hash", "nothrow @nogc hash.hash!(char[], indexing_postings.indexing_postings!(7).indexing_postings, 24).hash hash.hash!(char[], indexing_postings.indexing_postings!(7).indexing_postings, 24).hash.__ctor(allocator.allocator)"], 1363 ["_D4hash115__T4hashTAaTS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postingsVii24Z4hash7opIndexMFNcKxAaZS17indexing_postings56__T17indexing_postingsVE17indexing_postings9attributei7Z17indexing_postings", "ref indexing_postings.indexing_postings!(7).indexing_postings hash.hash!(char[], indexing_postings.indexing_postings!(7).indexing_postings, 24).hash.opIndex(ref const(char[]))"], 1364 ["_D9allocator9allocator13system_mallocMFNbNiNemZPg", "nothrow @nogc @trusted byte* allocator.allocator.system_malloc(ulong)"], 1365 ["_D9allocator9allocator6__ctorMFNaNbNiNfmZC9allocator9allocator", "pure nothrow @nogc @safe allocator.allocator allocator.allocator.__ctor(ulong)"], 1366 ["_D9allocator9allocator6mallocMFNbNiNemZAg", "nothrow @nogc @trusted byte[] allocator.allocator.malloc(ulong)"], 1367 ["_D9tokenizer9tokenizer10set_sourceMFAaZv", "void tokenizer.tokenizer.set_source(char[])"], 1368 ["_D9tokenizer9tokenizer12__T5parseTmZ5parseMFNaNbNiNemZAa", "pure nothrow @nogc @trusted char[] tokenizer.tokenizer.parse!(ulong).parse(ulong)"], 1369 ["_Dmain", "int main(string[] args)"], 1370 1371 /* 1372 These came from the D runtime core.demangle.d code base. That code contains the following Copyright notice. The "accompanying file LICENSE" is here: http://www.boost.org/LICENSE_1_0.txt 1373 Copyright: Copyright Sean Kelly 2010 - 2014. 1374 License: Distributed under the 1375 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 1376 (See accompanying file LICENSE) 1377 Authors: Sean Kelly 1378 Source: $(DRUNTIMESRC core/_demangle.d) 1379 */ 1380 ["printf", "printf"], 1381 ["_foo", "_foo"], 1382 ["_D88", "_D88"], 1383 ["_D4test3fooAa", "char[] test.foo"], 1384 ["_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])"], 1385 ["_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(Object)"], 1386 ["_D4test2dgDFiYd", "double test.dg(int, ...)"], 1387 //["_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", ""], 1388 //["_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", ""], 1389 ["_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(\"abc\"w, \"def\"d).x"], 1390 ["_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy Object, lazy int delegate(lazy int))"], 1391 ["_D8demangle4testFAiXi", "int demangle.test(int[]...)"], 1392 ["_D8demangle4testFAiYi", "int demangle.test(int[], ...)"], 1393 ["_D8demangle4testFLAiXi", "int demangle.test(lazy int[]...)"], 1394 ["_D8demangle4testFLAiYi", "int demangle.test(lazy int[], ...)"], 1395 ["_D6plugin8generateFiiZAya", "immutable(char)[] plugin.generate(int, int)"], 1396 ["_D6plugin8generateFiiZAxa", "const(char)[] plugin.generate(int, int)"], 1397 ["_D6plugin8generateFiiZAOa", "shared(char)[] plugin.generate(int, int)"], 1398 ["_D8demangle3fnAFZ3fnBMFZv", "void demangle.fnA().fnB()"], 1399 ["_D8demangle4mainFZ1S3fnCMFZv", "void demangle.main().S.fnC()"], 1400 ["_D8demangle4mainFZ1S3fnDMFZv", "void demangle.main().S.fnD()"], 1401 ["_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv", "void demangle.fn!([1, 2, 3, 4]).fn()"], 1402 ["_D8demangle10__T2fnVi1Z2fnFZv", "void demangle.fn!(1).fn()"], 1403 ["_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv", "void demangle.fn!(demangle.S(1, 2)).fn()"], 1404 ["_D8demangle13__T2fnVeeNANZ2fnFZv", "void demangle.fn!(real.nan).fn()"], 1405 ["_D8demangle14__T2fnVeeNINFZ2fnFZv", "void demangle.fn!(-real.infinity).fn()"], 1406 ["_D8demangle13__T2fnVeeINFZ2fnFZv", "void demangle.fn!(real.infinity).fn()"], 1407 ["_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv", "void demangle.fn!([1:2, 3:4]).fn()"], 1408 ["_D8demangle2fnFNgiZNgi", "inout int demangle.fn(inout(int))"], 1409 ["_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv", "void demangle.fn!('a', '\\t', \\x00, '\\u0101', '\\U00010001').fn()"], 1410 ["_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv", 1411 "nothrow @nogc @safe void gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)"], 1412 ["_D8serenity9persister6Sqlite69__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZ4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZ4Test", 1413 "serenity.persister.Sqlite.__unittest6().Test serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)"], 1414 ["_D8bug100274mainFZ5localMFZi","int bug10027.main().local()"], 1415 ["_D8demangle4testFNhG16gZv", "void demangle.test(__vector(byte[16]))"], 1416 ["_D8demangle4testFNhG8sZv", "void demangle.test(__vector(short[8]))"], 1417 ["_D8demangle4testFNhG4iZv", "void demangle.test(__vector(int[4]))"], 1418 ["_D8demangle4testFNhG2lZv", "void demangle.test(__vector(long[2]))"], 1419 ["_D8demangle4testFNhG4fZv", "void demangle.test(__vector(float[4]))"], 1420 ["_D8demangle4testFNhG2dZv", "void demangle.test(__vector(double[2]))"], 1421 ["_D8demangle4testFNhG4fNhG4fZv", "void demangle.test(__vector(float[4]), __vector(float[4]))"], 1422 ["_D8bug1119234__T3fooS23_D8bug111924mainFZ3bariZ3fooMFZv","void bug11192.foo!(int bug11192.main().bar).foo()"], 1423 ["_D13libd_demangle12__ModuleInfoZ", "libd_demangle.__ModuleInfo"], 1424 ["_D15TypeInfo_Struct6__vtblZ", "TypeInfo_Struct.__vtbl"], 1425 ["_D3std5stdio12__ModuleInfoZ", "std.stdio.__ModuleInfo"], 1426 ["_D3std6traits15__T8DemangleTkZ8Demangle6__initZ", "std.traits.Demangle!(uint).Demangle.__init"], 1427 ["_D3foo3Bar7__ClassZ", "foo.Bar.__Class"], 1428 ["_D3foo3Bar6__vtblZ", "foo.Bar.__vtbl"], 1429 ["_D3foo3Bar11__interfaceZ", "foo.Bar.__interface"], 1430 ["_D3foo7__arrayZ", "foo.__array"], 1431 ["_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"], 1432 ["_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"], 1433 ["_D4test22__T4funcVAyaa3_610a62Z4funcFNaNbNiNfZAya", `pure nothrow @nogc @safe immutable(char)[] test.func!("a\x0ab").func()`], 1434 ["_D3foo3barFzkZzi", "cent foo.bar(ucent)"], 1435 ];