1 module core.demangle; 2 3 // version (CRuntime_LIBWASM) This was made mostly nothrow 4 5 private struct NoHooks 6 { 7 // supported hooks 8 // static bool parseLName(ref Demangle); 9 // static char[] parseType(ref Demangle, char[]) 10 } 11 12 private struct Demangle(Hooks = NoHooks) 13 { 14 // NOTE: This implementation currently only works with mangled function 15 // names as they exist in an object file. Type names mangled via 16 // the .mangleof property are effectively incomplete as far as the 17 // ABI is concerned and so are not considered to be mangled symbol 18 // names. 19 20 // NOTE: This implementation builds the demangled buffer in place by 21 // writing data as it is decoded and then rearranging it later as 22 // needed. In practice this results in very little data movement, 23 // and the performance cost is more than offset by the gain from 24 // not allocating dynamic memory to assemble the name piecemeal. 25 // 26 // If the destination buffer is too small, parsing will restart 27 // with a larger buffer. Since this generally means only one 28 // allocation during the course of a parsing run, this is still 29 // faster than assembling the result piecemeal. 30 31 pure @safe nothrow: 32 enum AddType { no, yes } 33 34 35 this( return scope const(char)[] buf_, return scope char[] dst_ = null ) 36 { 37 this( buf_, AddType.yes, dst_ ); 38 } 39 40 41 this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null ) 42 { 43 buf = buf_; 44 addType = addType_; 45 dst = dst_; 46 } 47 48 49 enum size_t minBufSize = 4000; 50 51 52 const(char)[] buf = null; 53 char[] dst = null; 54 size_t pos = 0; 55 size_t len = 0; 56 size_t brp = 0; // current back reference pos 57 AddType addType = AddType.yes; 58 bool mute = false; 59 Hooks hooks; 60 61 static class ParseException : Exception 62 { 63 @safe pure nothrow this( string msg ) 64 { 65 super( msg ); 66 } 67 } 68 69 70 static class OverflowException : Exception 71 { 72 @safe pure nothrow this( string msg ) 73 { 74 super( msg ); 75 } 76 } 77 78 79 static void error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */ 80 { 81 pragma(inline, false); // tame dmd inliner 82 83 //throw new ParseException( msg ); 84 debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); 85 assert(0, msg); 86 // throw __ctfe ? new ParseException(msg) 87 // : cast(ParseException) __traits(initSymbol, ParseException).ptr; 88 } 89 90 91 static void overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */ 92 { 93 pragma(inline, false); // tame dmd inliner 94 95 //throw new OverflowException( msg ); 96 assert(0, msg); 97 // debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); 98 // throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr; 99 } 100 101 102 ////////////////////////////////////////////////////////////////////////// 103 // Type Testing and Conversion 104 ////////////////////////////////////////////////////////////////////////// 105 106 107 static bool isAlpha( char val ) 108 { 109 return ('a' <= val && 'z' >= val) || 110 ('A' <= val && 'Z' >= val) || 111 (0x80 & val); // treat all unicode as alphabetic 112 } 113 114 115 static bool isDigit( char val ) 116 { 117 return '0' <= val && '9' >= val; 118 } 119 120 121 static bool isHexDigit( char val ) 122 { 123 return ('0' <= val && '9' >= val) || 124 ('a' <= val && 'f' >= val) || 125 ('A' <= val && 'F' >= val); 126 } 127 128 129 static ubyte ascii2hex( char val ) 130 { 131 if (val >= 'a' && val <= 'f') 132 return cast(ubyte)(val - 'a' + 10); 133 if (val >= 'A' && val <= 'F') 134 return cast(ubyte)(val - 'A' + 10); 135 if (val >= '0' && val <= '9') 136 return cast(ubyte)(val - '0'); 137 error(); 138 return 0; 139 } 140 141 142 ////////////////////////////////////////////////////////////////////////// 143 // Data Output 144 ////////////////////////////////////////////////////////////////////////// 145 146 147 static bool contains( const(char)[] a, const(char)[] b ) @trusted 148 { 149 if (a.length && b.length) 150 { 151 auto bend = b.ptr + b.length; 152 auto aend = a.ptr + a.length; 153 return a.ptr <= b.ptr && bend <= aend; 154 } 155 return false; 156 } 157 158 159 // move val to the end of the dst buffer 160 char[] shift( const(char)[] val ) 161 { 162 pragma(inline, false); // tame dmd inliner 163 164 if ( val.length && !mute ) 165 { 166 assert( contains( dst[0 .. len], val ) ); 167 debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr ); 168 169 if (len + val.length > dst.length) 170 overflow(); 171 size_t v = &val[0] - &dst[0]; 172 dst[len .. len + val.length] = val[]; 173 for (size_t p = v; p < len; p++) 174 dst[p] = dst[p + val.length]; 175 176 return dst[len - val.length .. len]; 177 } 178 return null; 179 } 180 181 // remove val from dst buffer 182 void remove( const(char)[] val ) 183 { 184 pragma(inline, false); // tame dmd inliner 185 186 if ( val.length ) 187 { 188 assert( contains( dst[0 .. len], val ) ); 189 debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr ); 190 size_t v = &val[0] - &dst[0]; 191 assert( len >= val.length && len <= dst.length ); 192 len -= val.length; 193 for (size_t p = v; p < len; p++) 194 dst[p] = dst[p + val.length]; 195 } 196 } 197 198 char[] append( const(char)[] val ) return scope 199 { 200 pragma(inline, false); // tame dmd inliner 201 202 if ( val.length && !mute ) 203 { 204 if ( !dst.length ) 205 dst.length = minBufSize; 206 assert( !contains( dst[0 .. len], val ) ); 207 debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr ); 208 209 if ( dst.length - len >= val.length && &dst[len] == &val[0] ) 210 { 211 // data is already in place 212 auto t = dst[len .. len + val.length]; 213 len += val.length; 214 return t; 215 } 216 if ( dst.length - len >= val.length ) 217 { 218 dst[len .. len + val.length] = val[]; 219 auto t = dst[len .. len + val.length]; 220 len += val.length; 221 return t; 222 } 223 overflow(); 224 } 225 return null; 226 } 227 228 void putComma(size_t n) 229 { 230 pragma(inline, false); 231 if (n) 232 put(", "); 233 } 234 235 char[] put(char c) return scope 236 { 237 char[1] val = c; 238 return put(val[]); 239 } 240 241 char[] put( scope const(char)[] val ) return scope 242 { 243 pragma(inline, false); // tame dmd inliner 244 245 if ( val.length ) 246 { 247 if ( !contains( dst[0 .. len], val ) ) 248 return append( val ); 249 return shift( val ); 250 } 251 return null; 252 } 253 254 255 void putAsHex( size_t val, int width = 0 ) 256 { 257 import core.internal.string; 258 259 UnsignedStringBuf buf = void; 260 261 auto s = unsignedToTempString!16(val, buf); 262 int slen = cast(int)s.length; 263 if (slen < width) 264 { 265 foreach (i; slen .. width) 266 put('0'); 267 } 268 put(s); 269 } 270 271 272 void pad( const(char)[] val ) 273 { 274 if ( val.length ) 275 { 276 append( " " ); 277 put( val ); 278 } 279 } 280 281 282 void silent( void delegate() pure @safe nothrow dg ) 283 { 284 debug(trace) printf( "silent+\n" ); 285 debug(trace) scope(success) printf( "silent-\n" ); 286 auto n = len; dg(); len = n; 287 } 288 289 290 ////////////////////////////////////////////////////////////////////////// 291 // Parsing Utility 292 ////////////////////////////////////////////////////////////////////////// 293 294 @property bool empty() 295 { 296 return pos >= buf.length; 297 } 298 299 @property char front() 300 { 301 if ( pos < buf.length ) 302 return buf[pos]; 303 return char.init; 304 } 305 306 char peek( size_t n ) 307 { 308 if ( pos + n < buf.length ) 309 return buf[pos + n]; 310 return char.init; 311 } 312 313 314 void test( char val ) 315 { 316 if ( val != front ) 317 error(); 318 } 319 320 321 void popFront() 322 { 323 if ( pos++ >= buf.length ) 324 error(); 325 } 326 327 328 void popFront(int i) 329 { 330 while (i--) 331 popFront(); 332 } 333 334 335 void match( char val ) 336 { 337 test( val ); 338 popFront(); 339 } 340 341 342 void match( const(char)[] val ) 343 { 344 foreach (char e; val ) 345 { 346 test( e ); 347 popFront(); 348 } 349 } 350 351 352 void eat( char val ) 353 { 354 if ( val == front ) 355 popFront(); 356 } 357 358 bool isSymbolNameFront() 359 { 360 char val = front; 361 if ( isDigit( val ) || val == '_' ) 362 return true; 363 if ( val != 'Q' ) 364 return false; 365 366 // check the back reference encoding after 'Q' 367 val = peekBackref(); 368 return isDigit( val ); // identifier ref 369 } 370 371 // return the first character at the back reference 372 char peekBackref() 373 { 374 assert( front == 'Q' ); 375 auto n = decodeBackref!1(); 376 if (!n || n > pos) 377 error("invalid back reference"); 378 379 return buf[pos - n]; 380 } 381 382 size_t decodeBackref(size_t peekAt = 0)() 383 { 384 enum base = 26; 385 size_t n = 0; 386 for (size_t p; ; p++) 387 { 388 char t; 389 static if (peekAt > 0) 390 { 391 t = peek(peekAt + p); 392 } 393 else 394 { 395 t = front; 396 popFront(); 397 } 398 if (t < 'A' || t > 'Z') 399 { 400 if (t < 'a' || t > 'z') 401 error("invalid back reference"); 402 n = base * n + t - 'a'; 403 return n; 404 } 405 n = base * n + t - 'A'; 406 } 407 } 408 409 ////////////////////////////////////////////////////////////////////////// 410 // Parsing Implementation 411 ////////////////////////////////////////////////////////////////////////// 412 413 414 /* 415 Number: 416 Digit 417 Digit Number 418 */ 419 const(char)[] sliceNumber() return scope 420 { 421 debug(trace) printf( "sliceNumber+\n" ); 422 debug(trace) scope(success) printf( "sliceNumber-\n" ); 423 424 auto beg = pos; 425 426 while ( true ) 427 { 428 auto t = front; 429 if (t >= '0' && t <= '9') 430 popFront(); 431 else 432 return buf[beg .. pos]; 433 } 434 } 435 436 437 size_t decodeNumber() scope 438 { 439 debug(trace) printf( "decodeNumber+\n" ); 440 debug(trace) scope(success) printf( "decodeNumber-\n" ); 441 442 return decodeNumber( sliceNumber() ); 443 } 444 445 446 size_t decodeNumber( scope const(char)[] num ) scope 447 { 448 debug(trace) printf( "decodeNumber+\n" ); 449 debug(trace) scope(success) printf( "decodeNumber-\n" ); 450 451 size_t val = 0; 452 453 foreach ( c; num ) 454 { 455 import core.checkedint : mulu, addu; 456 457 bool overflow = false; 458 val = mulu(val, 10, overflow); 459 val = addu(val, c - '0', overflow); 460 if (overflow) 461 error(); 462 } 463 return val; 464 } 465 466 467 void parseReal() scope 468 { 469 debug(trace) printf( "parseReal+\n" ); 470 debug(trace) scope(success) printf( "parseReal-\n" ); 471 472 char[64] tbuf = void; 473 size_t tlen = 0; 474 real val = void; 475 476 if ( 'I' == front ) 477 { 478 match( "INF" ); 479 put( "real.infinity" ); 480 return; 481 } 482 if ( 'N' == front ) 483 { 484 popFront(); 485 if ( 'I' == front ) 486 { 487 match( "INF" ); 488 put( "-real.infinity" ); 489 return; 490 } 491 if ( 'A' == front ) 492 { 493 match( "AN" ); 494 put( "real.nan" ); 495 return; 496 } 497 tbuf[tlen++] = '-'; 498 } 499 500 tbuf[tlen++] = '0'; 501 tbuf[tlen++] = 'X'; 502 if ( !isHexDigit( front ) ) 503 error( "Expected hex digit" ); 504 tbuf[tlen++] = front; 505 tbuf[tlen++] = '.'; 506 popFront(); 507 508 while ( isHexDigit( front ) ) 509 { 510 tbuf[tlen++] = front; 511 popFront(); 512 } 513 match( 'P' ); 514 tbuf[tlen++] = 'p'; 515 if ( 'N' == front ) 516 { 517 tbuf[tlen++] = '-'; 518 popFront(); 519 } 520 else 521 { 522 tbuf[tlen++] = '+'; 523 } 524 while ( isDigit( front ) ) 525 { 526 tbuf[tlen++] = front; 527 popFront(); 528 } 529 530 tbuf[tlen] = 0; 531 debug(info) printf( "got (%s)\n", tbuf.ptr ); 532 //pureReprintReal( tbuf[] ); 533 debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr ); 534 put( tbuf[0 .. tlen] ); 535 } 536 537 538 /* 539 LName: 540 Number Name 541 542 Name: 543 Namestart 544 Namestart Namechars 545 546 Namestart: 547 _ 548 Alpha 549 550 Namechar: 551 Namestart 552 Digit 553 554 Namechars: 555 Namechar 556 Namechar Namechars 557 */ 558 void parseLName() scope 559 { 560 debug(trace) printf( "parseLName+\n" ); 561 debug(trace) scope(success) printf( "parseLName-\n" ); 562 563 static if (__traits(hasMember, Hooks, "parseLName")) 564 if (hooks.parseLName(this)) 565 return; 566 567 if ( front == 'Q' ) 568 { 569 // back reference to LName 570 auto refPos = pos; 571 popFront(); 572 size_t n = decodeBackref(); 573 if ( !n || n > refPos ) 574 error( "Invalid LName back reference" ); 575 if ( !mute ) 576 { 577 auto savePos = pos; 578 pos = refPos - n; 579 parseLName(); 580 pos = savePos; 581 } 582 return; 583 } 584 auto n = decodeNumber(); 585 if ( n == 0 ) 586 { 587 put( "__anonymous" ); 588 return; 589 } 590 if ( n > buf.length || n > buf.length - pos ) 591 error( "LName must be at least 1 character" ); 592 if ( '_' != front && !isAlpha( front ) ) 593 error( "Invalid character in LName" ); 594 foreach (char e; buf[pos + 1 .. pos + n] ) 595 { 596 if ( '_' != e && !isAlpha( e ) && !isDigit( e ) ) 597 error( "Invalid character in LName" ); 598 } 599 600 put( buf[pos .. pos + n] ); 601 pos += n; 602 } 603 604 605 /* 606 Type: 607 Shared 608 Const 609 Immutable 610 Wild 611 TypeArray 612 TypeVector 613 TypeStaticArray 614 TypeAssocArray 615 TypePointer 616 TypeFunction 617 TypeIdent 618 TypeClass 619 TypeStruct 620 TypeEnum 621 TypeTypedef 622 TypeDelegate 623 TypeNone 624 TypeVoid 625 TypeNoreturn 626 TypeByte 627 TypeUbyte 628 TypeShort 629 TypeUshort 630 TypeInt 631 TypeUint 632 TypeLong 633 TypeUlong 634 TypeCent 635 TypeUcent 636 TypeFloat 637 TypeDouble 638 TypeReal 639 TypeIfloat 640 TypeIdouble 641 TypeIreal 642 TypeCfloat 643 TypeCdouble 644 TypeCreal 645 TypeBool 646 TypeChar 647 TypeWchar 648 TypeDchar 649 TypeTuple 650 651 Shared: 652 O Type 653 654 Const: 655 x Type 656 657 Immutable: 658 y Type 659 660 Wild: 661 Ng Type 662 663 TypeArray: 664 A Type 665 666 TypeVector: 667 Nh Type 668 669 TypeStaticArray: 670 G Number Type 671 672 TypeAssocArray: 673 H Type Type 674 675 TypePointer: 676 P Type 677 678 TypeFunction: 679 CallConvention FuncAttrs Arguments ArgClose Type 680 681 TypeIdent: 682 I LName 683 684 TypeClass: 685 C LName 686 687 TypeStruct: 688 S LName 689 690 TypeEnum: 691 E LName 692 693 TypeTypedef: 694 T LName 695 696 TypeDelegate: 697 D TypeFunction 698 699 TypeNone: 700 n 701 702 TypeVoid: 703 v 704 705 TypeNoreturn 706 Nn 707 708 TypeByte: 709 g 710 711 TypeUbyte: 712 h 713 714 TypeShort: 715 s 716 717 TypeUshort: 718 t 719 720 TypeInt: 721 i 722 723 TypeUint: 724 k 725 726 TypeLong: 727 l 728 729 TypeUlong: 730 m 731 732 TypeCent 733 zi 734 735 TypeUcent 736 zk 737 738 TypeFloat: 739 f 740 741 TypeDouble: 742 d 743 744 TypeReal: 745 e 746 747 TypeIfloat: 748 o 749 750 TypeIdouble: 751 p 752 753 TypeIreal: 754 j 755 756 TypeCfloat: 757 q 758 759 TypeCdouble: 760 r 761 762 TypeCreal: 763 c 764 765 TypeBool: 766 b 767 768 TypeChar: 769 a 770 771 TypeWchar: 772 u 773 774 TypeDchar: 775 w 776 777 TypeTuple: 778 B Number Arguments 779 */ 780 char[] parseType( char[] name = null ) return scope 781 { 782 static immutable string[23] primitives = [ 783 "char", // a 784 "bool", // b 785 "creal", // c 786 "double", // d 787 "real", // e 788 "float", // f 789 "byte", // g 790 "ubyte", // h 791 "int", // i 792 "ireal", // j 793 "uint", // k 794 "long", // l 795 "ulong", // m 796 null, // n 797 "ifloat", // o 798 "idouble", // p 799 "cfloat", // q 800 "cdouble", // r 801 "short", // s 802 "ushort", // t 803 "wchar", // u 804 "void", // v 805 "dchar", // w 806 ]; 807 808 static if (__traits(hasMember, Hooks, "parseType")) 809 if (auto n = hooks.parseType(this, name)) 810 return n; 811 812 debug(trace) printf( "parseType+\n" ); 813 debug(trace) scope(success) printf( "parseType-\n" ); 814 auto beg = len; 815 auto t = front; 816 817 char[] parseBackrefType(scope char[] delegate() pure @safe nothrow parseDg) pure @safe 818 { 819 if (pos == brp) 820 error("recursive back reference"); 821 auto refPos = pos; 822 popFront(); 823 auto n = decodeBackref(); 824 if (n == 0 || n > pos) 825 error("invalid back reference"); 826 if ( mute ) 827 return null; 828 auto savePos = pos; 829 auto saveBrp = brp; 830 // scope(success) { pos = savePos; brp = saveBrp; } 831 pos = refPos - n; 832 brp = refPos; 833 auto ret = parseDg(); 834 pos = savePos; brp = saveBrp; 835 return ret; 836 } 837 838 switch ( t ) 839 { 840 case 'Q': // Type back reference 841 return parseBackrefType( () => parseType( name ) ); 842 case 'O': // Shared (O Type) 843 popFront(); 844 put( "shared(" ); 845 parseType(); 846 put( ')' ); 847 pad( name ); 848 return dst[beg .. len]; 849 case 'x': // Const (x Type) 850 popFront(); 851 put( "const(" ); 852 parseType(); 853 put( ')' ); 854 pad( name ); 855 return dst[beg .. len]; 856 case 'y': // Immutable (y Type) 857 popFront(); 858 put( "immutable(" ); 859 parseType(); 860 put( ')' ); 861 pad( name ); 862 return dst[beg .. len]; 863 case 'N': 864 popFront(); 865 switch ( front ) 866 { 867 case 'n': // Noreturn 868 popFront(); 869 put("noreturn"); 870 return dst[beg .. len]; 871 case 'g': // Wild (Ng Type) 872 popFront(); 873 // TODO: Anything needed here? 874 put( "inout(" ); 875 parseType(); 876 put( ')' ); 877 return dst[beg .. len]; 878 case 'h': // TypeVector (Nh Type) 879 popFront(); 880 put( "__vector(" ); 881 parseType(); 882 put( ')' ); 883 return dst[beg .. len]; 884 default: 885 error(); 886 assert( 0 ); 887 } 888 case 'A': // TypeArray (A Type) 889 popFront(); 890 parseType(); 891 put( "[]" ); 892 pad( name ); 893 return dst[beg .. len]; 894 case 'G': // TypeStaticArray (G Number Type) 895 popFront(); 896 auto num = sliceNumber(); 897 parseType(); 898 put( '[' ); 899 put( num ); 900 put( ']' ); 901 pad( name ); 902 return dst[beg .. len]; 903 case 'H': // TypeAssocArray (H Type Type) 904 popFront(); 905 // skip t1 906 auto tx = parseType(); 907 parseType(); 908 put( '[' ); 909 put( tx ); 910 put( ']' ); 911 pad( name ); 912 return dst[beg .. len]; 913 case 'P': // TypePointer (P Type) 914 popFront(); 915 parseType(); 916 put( '*' ); 917 pad( name ); 918 return dst[beg .. len]; 919 case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction 920 return parseTypeFunction( name ); 921 case 'C': // TypeClass (C LName) 922 case 'S': // TypeStruct (S LName) 923 case 'E': // TypeEnum (E LName) 924 case 'T': // TypeTypedef (T LName) 925 popFront(); 926 parseQualifiedName(); 927 pad( name ); 928 return dst[beg .. len]; 929 case 'D': // TypeDelegate (D TypeFunction) 930 popFront(); 931 auto modbeg = len; 932 parseModifier(); 933 auto modend = len; 934 if ( front == 'Q' ) 935 parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) ); 936 else 937 parseTypeFunction( name, IsDelegate.yes ); 938 if (modend > modbeg) 939 { 940 // move modifiers behind the function arguments 941 shift(dst[modend-1 .. modend]); // trailing space 942 shift(dst[modbeg .. modend-1]); 943 } 944 return dst[beg .. len]; 945 case 'n': // TypeNone (n) 946 popFront(); 947 // TODO: Anything needed here? 948 return dst[beg .. len]; 949 case 'B': // TypeTuple (B Number Arguments) 950 popFront(); 951 // TODO: Handle this. 952 return dst[beg .. len]; 953 case 'Z': // Internal symbol 954 // This 'type' is used for untyped internal symbols, i.e.: 955 // __array 956 // __init 957 // __vtbl 958 // __Class 959 // __Interface 960 // __ModuleInfo 961 popFront(); 962 return dst[beg .. len]; 963 default: 964 if (t >= 'a' && t <= 'w') 965 { 966 popFront(); 967 put( primitives[cast(size_t)(t - 'a')] ); 968 pad( name ); 969 return dst[beg .. len]; 970 } 971 else if (t == 'z') 972 { 973 popFront(); 974 switch ( front ) 975 { 976 case 'i': 977 popFront(); 978 put( "cent" ); 979 pad( name ); 980 return dst[beg .. len]; 981 case 'k': 982 popFront(); 983 put( "ucent" ); 984 pad( name ); 985 return dst[beg .. len]; 986 default: 987 error(); 988 assert( 0 ); 989 } 990 } 991 error(); 992 return null; 993 } 994 } 995 996 997 /* 998 TypeFunction: 999 CallConvention FuncAttrs Arguments ArgClose Type 1000 1001 CallConvention: 1002 F // D 1003 U // C 1004 W // Windows 1005 R // C++ 1006 1007 FuncAttrs: 1008 FuncAttr 1009 FuncAttr FuncAttrs 1010 1011 FuncAttr: 1012 empty 1013 FuncAttrPure 1014 FuncAttrNothrow 1015 FuncAttrProperty 1016 FuncAttrRef 1017 FuncAttrReturn 1018 FuncAttrScope 1019 FuncAttrTrusted 1020 FuncAttrSafe 1021 1022 FuncAttrPure: 1023 Na 1024 1025 FuncAttrNothrow: 1026 Nb 1027 1028 FuncAttrRef: 1029 Nc 1030 1031 FuncAttrProperty: 1032 Nd 1033 1034 FuncAttrTrusted: 1035 Ne 1036 1037 FuncAttrSafe: 1038 Nf 1039 1040 FuncAttrNogc: 1041 Ni 1042 1043 FuncAttrReturn: 1044 Nj 1045 1046 FuncAttrScope: 1047 Nl 1048 1049 Arguments: 1050 Argument 1051 Argument Arguments 1052 1053 Argument: 1054 Argument2 1055 M Argument2 // scope 1056 1057 Argument2: 1058 Type 1059 J Type // out 1060 K Type // ref 1061 L Type // lazy 1062 1063 ArgClose 1064 X // variadic T t,...) style 1065 Y // variadic T t...) style 1066 Z // not variadic 1067 */ 1068 void parseCallConvention() 1069 { 1070 // CallConvention 1071 switch ( front ) 1072 { 1073 case 'F': // D 1074 popFront(); 1075 break; 1076 case 'U': // C 1077 popFront(); 1078 put( "extern (C) " ); 1079 break; 1080 case 'W': // Windows 1081 popFront(); 1082 put( "extern (Windows) " ); 1083 break; 1084 case 'R': // C++ 1085 popFront(); 1086 put( "extern (C++) " ); 1087 break; 1088 default: 1089 error(); 1090 } 1091 } 1092 1093 void parseModifier() 1094 { 1095 switch ( front ) 1096 { 1097 case 'y': 1098 popFront(); 1099 put( "immutable " ); 1100 break; 1101 case 'O': 1102 popFront(); 1103 put( "shared " ); 1104 if ( front == 'x' ) 1105 goto case 'x'; 1106 if ( front == 'N' ) 1107 goto case 'N'; 1108 break; 1109 case 'N': 1110 if ( peek( 1 ) != 'g' ) 1111 break; 1112 popFront(); 1113 popFront(); 1114 put( "inout " ); 1115 if ( front == 'x' ) 1116 goto case 'x'; 1117 break; 1118 case 'x': 1119 popFront(); 1120 put( "const " ); 1121 break; 1122 default: break; 1123 } 1124 } 1125 1126 void parseFuncAttr() 1127 { 1128 // FuncAttrs 1129 breakFuncAttrs: 1130 while ('N' == front) 1131 { 1132 popFront(); 1133 switch ( front ) 1134 { 1135 case 'a': // FuncAttrPure 1136 popFront(); 1137 put( "pure " ); 1138 continue; 1139 case 'b': // FuncAttrNoThrow 1140 popFront(); 1141 put( "nothrow " ); 1142 continue; 1143 case 'c': // FuncAttrRef 1144 popFront(); 1145 put( "ref " ); 1146 continue; 1147 case 'd': // FuncAttrProperty 1148 popFront(); 1149 put( "@property " ); 1150 continue; 1151 case 'e': // FuncAttrTrusted 1152 popFront(); 1153 put( "@trusted " ); 1154 continue; 1155 case 'f': // FuncAttrSafe 1156 popFront(); 1157 put( "@safe " ); 1158 continue; 1159 case 'g': 1160 case 'h': 1161 case 'k': 1162 case 'n': 1163 // NOTE: The inout parameter type is represented as "Ng". 1164 // The vector parameter type is represented as "Nh". 1165 // The return parameter type is represented as "Nk". 1166 // The noreturn parameter type is represented as "Nn". 1167 // These make it look like a FuncAttr, but infact 1168 // if we see these, then we know we're really in 1169 // the parameter list. Rewind and break. 1170 pos--; 1171 break breakFuncAttrs; 1172 case 'i': // FuncAttrNogc 1173 popFront(); 1174 put( "@nogc " ); 1175 continue; 1176 case 'j': // FuncAttrReturn 1177 popFront(); 1178 put( "return " ); 1179 continue; 1180 case 'l': // FuncAttrScope 1181 popFront(); 1182 put( "scope " ); 1183 continue; 1184 case 'm': // FuncAttrLive 1185 popFront(); 1186 put( "@live " ); 1187 continue; 1188 default: 1189 error(); 1190 } 1191 } 1192 } 1193 1194 void parseFuncArguments() scope 1195 { 1196 // Arguments 1197 for ( size_t n = 0; true; n++ ) 1198 { 1199 debug(info) printf( "tok (%c)\n", front ); 1200 switch ( front ) 1201 { 1202 case 'X': // ArgClose (variadic T t...) style) 1203 popFront(); 1204 put( "..." ); 1205 return; 1206 case 'Y': // ArgClose (variadic T t,...) style) 1207 popFront(); 1208 put( ", ..." ); 1209 return; 1210 case 'Z': // ArgClose (not variadic) 1211 popFront(); 1212 return; 1213 default: 1214 break; 1215 } 1216 putComma(n); 1217 1218 /* Do special return, scope, ref, out combinations 1219 */ 1220 int npops; 1221 if ( 'M' == front && peek(1) == 'N' && peek(2) == 'k') 1222 { 1223 const c3 = peek(3); 1224 if (c3 == 'J') 1225 { 1226 put("scope return out "); // MNkJ 1227 npops = 4; 1228 } 1229 else if (c3 == 'K') 1230 { 1231 put("scope return ref "); // MNkK 1232 npops = 4; 1233 } 1234 } 1235 else if ('N' == front && peek(1) == 'k') 1236 { 1237 const c2 = peek(2); 1238 if (c2 == 'J') 1239 { 1240 put("return out "); // NkJ 1241 npops = 3; 1242 } 1243 else if (c2 == 'K') 1244 { 1245 put("return ref "); // NkK 1246 npops = 3; 1247 } 1248 else if (c2 == 'M') 1249 { 1250 const c3 = peek(3); 1251 if (c3 == 'J') 1252 { 1253 put("return scope out "); // NkMJ 1254 npops = 4; 1255 } 1256 else if (c3 == 'K') 1257 { 1258 put("return scope ref "); // NkMK 1259 npops = 4; 1260 } 1261 else 1262 { 1263 put("return scope "); // NkM 1264 npops = 3; 1265 } 1266 } 1267 } 1268 popFront(npops); 1269 1270 if ( 'M' == front ) 1271 { 1272 popFront(); 1273 put( "scope " ); 1274 } 1275 if ( 'N' == front ) 1276 { 1277 popFront(); 1278 if ( 'k' == front ) // Return (Nk Parameter2) 1279 { 1280 popFront(); 1281 put( "return " ); 1282 } 1283 else 1284 pos--; 1285 } 1286 switch ( front ) 1287 { 1288 case 'I': // in (I Type) 1289 popFront(); 1290 put("in "); 1291 if (front == 'K') 1292 goto case; 1293 parseType(); 1294 continue; 1295 case 'K': // ref (K Type) 1296 popFront(); 1297 put( "ref " ); 1298 parseType(); 1299 continue; 1300 case 'J': // out (J Type) 1301 popFront(); 1302 put( "out " ); 1303 parseType(); 1304 continue; 1305 case 'L': // lazy (L Type) 1306 popFront(); 1307 put( "lazy " ); 1308 parseType(); 1309 continue; 1310 default: 1311 parseType(); 1312 } 1313 } 1314 } 1315 1316 enum IsDelegate { no, yes } 1317 1318 /* 1319 TypeFunction: 1320 CallConvention FuncAttrs Arguments ArgClose Type 1321 */ 1322 char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope 1323 { 1324 debug(trace) printf( "parseTypeFunction+\n" ); 1325 debug(trace) scope(success) printf( "parseTypeFunction-\n" ); 1326 auto beg = len; 1327 1328 parseCallConvention(); 1329 auto attrbeg = len; 1330 parseFuncAttr(); 1331 1332 auto argbeg = len; 1333 put( '(' ); 1334 parseFuncArguments(); 1335 put( ')' ); 1336 if (attrbeg < argbeg) 1337 { 1338 // move function attributes behind arguments 1339 shift( dst[argbeg - 1 .. argbeg] ); // trailing space 1340 shift( dst[attrbeg .. argbeg - 1] ); // attributes 1341 argbeg = attrbeg; 1342 } 1343 auto retbeg = len; 1344 parseType(); 1345 put( ' ' ); 1346 // append name/delegate/function 1347 if ( name.length ) 1348 { 1349 if ( !contains( dst[0 .. len], name ) ) 1350 put( name ); 1351 else if ( shift( name ).ptr != name.ptr ) 1352 { 1353 argbeg -= name.length; 1354 retbeg -= name.length; 1355 } 1356 } 1357 else if ( IsDelegate.yes == isdg ) 1358 put( "delegate" ); 1359 else 1360 put( "function" ); 1361 // move arguments and attributes behind name 1362 shift( dst[argbeg .. retbeg] ); 1363 return dst[beg..len]; 1364 } 1365 1366 static bool isCallConvention( char ch ) 1367 { 1368 switch ( ch ) 1369 { 1370 case 'F', 'U', 'V', 'W', 'R': 1371 return true; 1372 default: 1373 return false; 1374 } 1375 } 1376 1377 /* 1378 Value: 1379 n 1380 Number 1381 i Number 1382 N Number 1383 e HexFloat 1384 c HexFloat c HexFloat 1385 A Number Value... 1386 1387 HexFloat: 1388 NAN 1389 INF 1390 NINF 1391 N HexDigits P Exponent 1392 HexDigits P Exponent 1393 1394 Exponent: 1395 N Number 1396 Number 1397 1398 HexDigits: 1399 HexDigit 1400 HexDigit HexDigits 1401 1402 HexDigit: 1403 Digit 1404 A 1405 B 1406 C 1407 D 1408 E 1409 F 1410 */ 1411 void parseValue(scope char[] name = null, char type = '\0' ) scope 1412 { 1413 debug(trace) printf( "parseValue+\n" ); 1414 debug(trace) scope(success) printf( "parseValue-\n" ); 1415 1416 // printf( "*** %c\n", front ); 1417 switch ( front ) 1418 { 1419 case 'n': 1420 popFront(); 1421 put( "null" ); 1422 return; 1423 case 'i': 1424 popFront(); 1425 if ( '0' > front || '9' < front ) 1426 error( "Number expected" ); 1427 goto case; 1428 case '0': .. case '9': 1429 parseIntegerValue( name, type ); 1430 return; 1431 case 'N': 1432 popFront(); 1433 put( '-' ); 1434 parseIntegerValue( name, type ); 1435 return; 1436 case 'e': 1437 popFront(); 1438 parseReal(); 1439 return; 1440 case 'c': 1441 popFront(); 1442 parseReal(); 1443 put( '+' ); 1444 match( 'c' ); 1445 parseReal(); 1446 put( 'i' ); 1447 return; 1448 case 'a': case 'w': case 'd': 1449 char t = front; 1450 popFront(); 1451 auto n = decodeNumber(); 1452 match( '_' ); 1453 put( '"' ); 1454 foreach (i; 0..n) 1455 { 1456 auto a = ascii2hex( front ); popFront(); 1457 auto b = ascii2hex( front ); popFront(); 1458 auto v = cast(char)((a << 4) | b); 1459 if (' ' <= v && v <= '~') // ASCII printable 1460 { 1461 put(v); 1462 } 1463 else 1464 { 1465 put("\\x"); 1466 putAsHex(v, 2); 1467 } 1468 } 1469 put( '"' ); 1470 if ( 'a' != t ) 1471 put(t); 1472 return; 1473 case 'A': 1474 // NOTE: This is kind of a hack. An associative array literal 1475 // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type 1476 // is "Hii" and the value is "A2i1i2i3i4". Thus the only 1477 // way to determine that this is an AA value rather than an 1478 // array value is for the caller to supply the type char. 1479 // Hopefully, this will change so that the value is 1480 // "H2i1i2i3i4", rendering this unnecesary. 1481 if ( 'H' == type ) 1482 goto LassocArray; 1483 // A Number Value... 1484 // An array literal. Value is repeated Number times. 1485 popFront(); 1486 put( '[' ); 1487 auto n = decodeNumber(); 1488 foreach ( i; 0 .. n ) 1489 { 1490 putComma(i); 1491 parseValue(); 1492 } 1493 put( ']' ); 1494 return; 1495 case 'H': 1496 LassocArray: 1497 // H Number Value... 1498 // An associative array literal. Value is repeated 2*Number times. 1499 popFront(); 1500 put( '[' ); 1501 auto n = decodeNumber(); 1502 foreach ( i; 0 .. n ) 1503 { 1504 putComma(i); 1505 parseValue(); 1506 put(':'); 1507 parseValue(); 1508 } 1509 put( ']' ); 1510 return; 1511 case 'S': 1512 // S Number Value... 1513 // A struct literal. Value is repeated Number times. 1514 popFront(); 1515 if ( name.length ) 1516 put( name ); 1517 put( '(' ); 1518 auto n = decodeNumber(); 1519 foreach ( i; 0 .. n ) 1520 { 1521 putComma(i); 1522 parseValue(); 1523 } 1524 put( ')' ); 1525 return; 1526 case 'f': 1527 // f MangledName 1528 // A function literal symbol 1529 popFront(); 1530 parseMangledName(false, 1); 1531 return; 1532 default: 1533 error(); 1534 } 1535 } 1536 1537 1538 void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope 1539 { 1540 debug(trace) printf( "parseIntegerValue+\n" ); 1541 debug(trace) scope(success) printf( "parseIntegerValue-\n" ); 1542 1543 switch ( type ) 1544 { 1545 case 'a': // char 1546 case 'u': // wchar 1547 case 'w': // dchar 1548 { 1549 auto val = sliceNumber(); 1550 auto num = decodeNumber( val ); 1551 1552 switch ( num ) 1553 { 1554 case '\'': 1555 put( "'\\''" ); 1556 return; 1557 // \", \? 1558 case '\\': 1559 put( "'\\\\'" ); 1560 return; 1561 case '\a': 1562 put( "'\\a'" ); 1563 return; 1564 case '\b': 1565 put( "'\\b'" ); 1566 return; 1567 case '\f': 1568 put( "'\\f'" ); 1569 return; 1570 case '\n': 1571 put( "'\\n'" ); 1572 return; 1573 case '\r': 1574 put( "'\\r'" ); 1575 return; 1576 case '\t': 1577 put( "'\\t'" ); 1578 return; 1579 case '\v': 1580 put( "'\\v'" ); 1581 return; 1582 default: 1583 switch ( type ) 1584 { 1585 case 'a': 1586 if ( num >= 0x20 && num < 0x7F ) 1587 { 1588 put( '\'' ); 1589 put( cast(char)num ); 1590 put( '\'' ); 1591 return; 1592 } 1593 put( "\\x" ); 1594 putAsHex( num, 2 ); 1595 return; 1596 case 'u': 1597 put( "'\\u" ); 1598 putAsHex( num, 4 ); 1599 put( '\'' ); 1600 return; 1601 case 'w': 1602 put( "'\\U" ); 1603 putAsHex( num, 8 ); 1604 put( '\'' ); 1605 return; 1606 default: 1607 assert( 0 ); 1608 } 1609 } 1610 } 1611 case 'b': // bool 1612 put( decodeNumber() ? "true" : "false" ); 1613 return; 1614 case 'h', 't', 'k': // ubyte, ushort, uint 1615 put( sliceNumber() ); 1616 put( 'u' ); 1617 return; 1618 case 'l': // long 1619 put( sliceNumber() ); 1620 put( 'L' ); 1621 return; 1622 case 'm': // ulong 1623 put( sliceNumber() ); 1624 put( "uL" ); 1625 return; 1626 default: 1627 put( sliceNumber() ); 1628 return; 1629 } 1630 } 1631 1632 1633 /* 1634 TemplateArgs: 1635 TemplateArg 1636 TemplateArg TemplateArgs 1637 1638 TemplateArg: 1639 TemplateArgX 1640 H TemplateArgX 1641 1642 TemplateArgX: 1643 T Type 1644 V Type Value 1645 S Number_opt QualifiedName 1646 X ExternallyMangledName 1647 */ 1648 void parseTemplateArgs() scope 1649 { 1650 debug(trace) printf( "parseTemplateArgs+\n" ); 1651 debug(trace) scope(success) printf( "parseTemplateArgs-\n" ); 1652 1653 L_nextArg: 1654 for ( size_t n = 0; true; n++ ) 1655 { 1656 if ( front == 'H' ) 1657 popFront(); 1658 1659 switch ( front ) 1660 { 1661 case 'T': 1662 popFront(); 1663 putComma(n); 1664 parseType(); 1665 continue; 1666 case 'V': 1667 popFront(); 1668 putComma(n); 1669 // NOTE: In the few instances where the type is actually 1670 // desired in the output it should precede the value 1671 // generated by parseValue, so it is safe to simply 1672 // decrement len and let put/append do its thing. 1673 char t = front; // peek at type for parseValue 1674 if ( t == 'Q' ) 1675 t = peekBackref(); 1676 char[] name; silent( delegate void() { name = parseType(); } ); 1677 parseValue( name, t ); 1678 continue; 1679 case 'S': 1680 popFront(); 1681 putComma(n); 1682 1683 if ( mayBeMangledNameArg() ) 1684 { 1685 auto l = len; 1686 auto p = pos; 1687 auto b = brp; 1688 // try 1689 // { 1690 debug(trace) printf( "may be mangled name arg\n" ); 1691 parseMangledNameArg(); 1692 continue; 1693 // } 1694 // catch ( ParseException e ) 1695 // { 1696 // len = l; 1697 // pos = p; 1698 // brp = b; 1699 // debug(trace) printf( "not a mangled name arg\n" ); 1700 // } 1701 } 1702 if ( isDigit( front ) && isDigit( peek( 1 ) ) ) 1703 { 1704 // ambiguity: length followed by qualified name (starting with number) 1705 // try all possible pairs of numbers 1706 auto qlen = decodeNumber() / 10; // last digit needed for QualifiedName 1707 pos--; 1708 auto l = len; 1709 auto p = pos; 1710 auto b = brp; 1711 while ( qlen > 0 ) 1712 { 1713 // try 1714 // { 1715 parseQualifiedName(); 1716 if ( pos == p + qlen ) 1717 continue L_nextArg; 1718 // } 1719 // catch ( ParseException e ) 1720 // { 1721 // } 1722 qlen /= 10; // retry with one digit less 1723 pos = --p; 1724 len = l; 1725 brp = b; 1726 } 1727 } 1728 parseQualifiedName(); 1729 continue; 1730 case 'X': 1731 popFront(); 1732 putComma(n); 1733 parseLName(); 1734 continue; 1735 default: 1736 return; 1737 } 1738 } 1739 } 1740 1741 1742 bool mayBeMangledNameArg() 1743 { 1744 debug(trace) printf( "mayBeMangledNameArg+\n" ); 1745 debug(trace) scope(success) printf( "mayBeMangledNameArg-\n" ); 1746 1747 auto p = pos; 1748 if ( isDigit( buf[pos] ) ) 1749 { 1750 auto n = decodeNumber(); 1751 auto ret = n >= 4 && 1752 pos < buf.length && '_' == buf[pos++] && 1753 pos < buf.length && 'D' == buf[pos++] && 1754 isDigit( buf[pos] ); 1755 pos = p; 1756 return ret; 1757 } 1758 else 1759 { 1760 auto ret = pos < buf.length && '_' == buf[pos++] && 1761 pos < buf.length && 'D' == buf[pos++] && 1762 isSymbolNameFront(); 1763 pos = p; 1764 return ret; 1765 } 1766 } 1767 1768 1769 void parseMangledNameArg() 1770 { 1771 debug(trace) printf( "parseMangledNameArg+\n" ); 1772 debug(trace) scope(success) printf( "parseMangledNameArg-\n" ); 1773 1774 size_t n = 0; 1775 if ( isDigit( front ) ) 1776 n = decodeNumber(); 1777 parseMangledName( false, n ); 1778 } 1779 1780 1781 /* 1782 TemplateInstanceName: 1783 Number __T LName TemplateArgs Z 1784 */ 1785 void parseTemplateInstanceName(bool hasNumber) scope 1786 { 1787 debug(trace) printf( "parseTemplateInstanceName+\n" ); 1788 debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" ); 1789 1790 auto sav = pos; 1791 auto saveBrp = brp; 1792 // scope(failure) 1793 // { 1794 // pos = sav; 1795 // brp = saveBrp; 1796 // } 1797 auto n = hasNumber ? decodeNumber() : 0; 1798 auto beg = pos; 1799 match( "__T" ); 1800 parseLName(); 1801 put( "!(" ); 1802 parseTemplateArgs(); 1803 match( 'Z' ); 1804 if ( hasNumber && pos - beg != n ) 1805 error( "Template name length mismatch" ); 1806 put( ')' ); 1807 } 1808 1809 1810 bool mayBeTemplateInstanceName() scope 1811 { 1812 debug(trace) printf( "mayBeTemplateInstanceName+\n" ); 1813 debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" ); 1814 1815 auto p = pos; 1816 //scope(exit) pos = p; 1817 auto n = decodeNumber(); 1818 auto ret = n >= 5 && 1819 pos < buf.length && '_' == buf[pos++] && 1820 pos < buf.length && '_' == buf[pos++] && 1821 pos < buf.length && 'T' == buf[pos++]; 1822 pos = p; 1823 return ret; 1824 } 1825 1826 1827 /* 1828 SymbolName: 1829 LName 1830 TemplateInstanceName 1831 */ 1832 void parseSymbolName() scope 1833 { 1834 debug(trace) printf( "parseSymbolName+\n" ); 1835 debug(trace) scope(success) printf( "parseSymbolName-\n" ); 1836 1837 // LName -> Number 1838 // TemplateInstanceName -> Number "__T" 1839 switch ( front ) 1840 { 1841 case '_': 1842 // no length encoding for templates for new mangling 1843 parseTemplateInstanceName(false); 1844 return; 1845 1846 case '0': .. case '9': 1847 if ( mayBeTemplateInstanceName() ) 1848 { 1849 auto t = len; 1850 1851 // try 1852 // { 1853 debug(trace) printf( "may be template instance name\n" ); 1854 parseTemplateInstanceName(true); 1855 return; 1856 // } 1857 // catch ( ParseException e ) 1858 // { 1859 // debug(trace) printf( "not a template instance name\n" ); 1860 // len = t; 1861 // } 1862 } 1863 goto case; 1864 case 'Q': 1865 parseLName(); 1866 return; 1867 default: 1868 error(); 1869 } 1870 } 1871 1872 // parse optional function arguments as part of a symbol name, i.e without return type 1873 // if keepAttr, the calling convention and function attributes are not discarded, but returned 1874 char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope 1875 { 1876 // try to demangle a function, in case we are pointing to some function local 1877 auto prevpos = pos; 1878 auto prevlen = len; 1879 auto prevbrp = brp; 1880 1881 char[] attr; 1882 // try 1883 // { 1884 if ( 'M' == front ) 1885 { 1886 // do not emit "needs this" 1887 popFront(); 1888 parseModifier(); 1889 } 1890 if ( isCallConvention( front ) ) 1891 { 1892 // we don't want calling convention and attributes in the qualified name 1893 parseCallConvention(); 1894 parseFuncAttr(); 1895 if ( keepAttr ) 1896 { 1897 attr = dst[prevlen .. len]; 1898 } 1899 else 1900 { 1901 len = prevlen; 1902 } 1903 1904 put( '(' ); 1905 parseFuncArguments(); 1906 put( ')' ); 1907 } 1908 // } 1909 // catch ( ParseException ) 1910 // { 1911 // // not part of a qualified name, so back up 1912 // pos = prevpos; 1913 // len = prevlen; 1914 // brp = prevbrp; 1915 // attr = null; 1916 // } 1917 return attr; 1918 } 1919 1920 /* 1921 QualifiedName: 1922 SymbolName 1923 SymbolName QualifiedName 1924 */ 1925 char[] parseQualifiedName() return scope 1926 { 1927 debug(trace) printf( "parseQualifiedName+\n" ); 1928 debug(trace) scope(success) printf( "parseQualifiedName-\n" ); 1929 size_t beg = len; 1930 size_t n = 0; 1931 1932 do 1933 { 1934 if ( n++ ) 1935 put( '.' ); 1936 parseSymbolName(); 1937 parseFunctionTypeNoReturn(); 1938 1939 } while ( isSymbolNameFront() ); 1940 return dst[beg .. len]; 1941 } 1942 1943 1944 /* 1945 MangledName: 1946 _D QualifiedName Type 1947 _D QualifiedName M Type 1948 */ 1949 void parseMangledName( bool displayType, size_t n = 0 ) scope 1950 { 1951 debug(trace) printf( "parseMangledName+\n" ); 1952 debug(trace) scope(success) printf( "parseMangledName-\n" ); 1953 char[] name = null; 1954 1955 auto end = pos + n; 1956 1957 eat( '_' ); 1958 match( 'D' ); 1959 do 1960 { 1961 size_t beg = len; 1962 size_t nameEnd = len; 1963 char[] attr; 1964 do 1965 { 1966 if ( attr ) 1967 remove( attr ); // dump attributes of parent symbols 1968 if ( beg != len ) 1969 put( '.' ); 1970 parseSymbolName(); 1971 nameEnd = len; 1972 attr = parseFunctionTypeNoReturn( displayType ); 1973 1974 } while ( isSymbolNameFront() ); 1975 1976 if ( displayType ) 1977 { 1978 attr = shift( attr ); 1979 nameEnd = len - attr.length; // name includes function arguments 1980 } 1981 name = dst[beg .. nameEnd]; 1982 1983 debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr ); 1984 if ( 'M' == front ) 1985 popFront(); // has 'this' pointer 1986 1987 auto lastlen = len; 1988 auto type = parseType(); 1989 if ( displayType ) 1990 { 1991 if ( type.length ) 1992 put( ' ' ); 1993 // sort (name,attr,type) -> (attr,type,name) 1994 shift( name ); 1995 } 1996 else 1997 { 1998 // remove type 1999 assert( attr.length == 0 ); 2000 len = lastlen; 2001 } 2002 if ( pos >= buf.length || (n != 0 && pos >= end) ) 2003 return; 2004 2005 switch ( front ) 2006 { 2007 case 'T': // terminators when used as template alias parameter 2008 case 'V': 2009 case 'S': 2010 case 'Z': 2011 return; 2012 default: 2013 } 2014 put( '.' ); 2015 2016 } while ( true ); 2017 } 2018 2019 void parseMangledName() 2020 { 2021 parseMangledName( AddType.yes == addType ); 2022 } 2023 2024 char[] copyInput() return scope 2025 { 2026 if (dst.length < buf.length) 2027 dst.length = buf.length; 2028 char[] r = dst[0 .. buf.length]; 2029 r[] = buf[]; 2030 return r; 2031 } 2032 2033 char[] doDemangle(alias FUNC)() return scope 2034 { 2035 while ( true ) 2036 { 2037 // try 2038 // { 2039 debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr ); 2040 FUNC(); 2041 return dst[0 .. len]; 2042 // } 2043 // catch ( OverflowException e ) 2044 // { 2045 // debug(trace) printf( "overflow... restarting\n" ); 2046 // auto a = minBufSize; 2047 // auto b = 2 * dst.length; 2048 // auto newsz = a < b ? b : a; 2049 // debug(info) printf( "growing dst to %lu bytes\n", newsz ); 2050 // dst.length = newsz; 2051 // pos = len = brp = 0; 2052 // continue; 2053 // } 2054 // catch ( ParseException e ) 2055 // { 2056 // debug(info) 2057 // { 2058 // auto msg = e.toString(); 2059 // printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); 2060 // } 2061 // return copyInput(); 2062 // } 2063 // catch ( Exception e ) 2064 // { 2065 // assert( false ); // no other exceptions thrown 2066 // } 2067 } 2068 } 2069 2070 char[] demangleName() nothrow 2071 { 2072 return doDemangle!parseMangledName(); 2073 } 2074 2075 char[] demangleType() nothrow 2076 { 2077 return doDemangle!parseType(); 2078 } 2079 } 2080 2081 2082 /** 2083 * Demangles D mangled names. If it is not a D mangled name, it returns its 2084 * argument name. 2085 * 2086 * Params: 2087 * buf = The string to demangle. 2088 * dst = An optional destination buffer. 2089 * 2090 * Returns: 2091 * The demangled name or the original string if the name is not a mangled D 2092 * name. 2093 */ 2094 char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe 2095 { 2096 auto d = Demangle!()(buf, dst); 2097 // fast path (avoiding throwing & catching exception) for obvious 2098 // non-D mangled names 2099 if (buf.length < 2 || !(buf[0] == 'D' || buf[0..2] == "_D")) 2100 return d.copyInput(); 2101 return d.demangleName(); 2102 } 2103 2104 2105 /** 2106 * Demangles a D mangled type. 2107 * 2108 * Params: 2109 * buf = The string to demangle. 2110 * dst = An optional destination buffer. 2111 * 2112 * Returns: 2113 * The demangled type name or the original string if the name is not a 2114 * mangled D type. 2115 */ 2116 char[] demangleType( const(char)[] buf, char[] dst = null ) nothrow pure @safe 2117 { 2118 auto d = Demangle!()(buf, dst); 2119 return d.demangleType(); 2120 } 2121 2122 /** 2123 * reencode a mangled symbol name that might include duplicate occurrences 2124 * of the same identifier by replacing all but the first occurence with 2125 * a back reference. 2126 * 2127 * Params: 2128 * mangled = The mangled string representing the type 2129 * 2130 * Returns: 2131 * The mangled name with deduplicated identifiers 2132 */ 2133 char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe 2134 { 2135 static struct PrependHooks 2136 { 2137 size_t lastpos; 2138 char[] result; 2139 size_t[const(char)[]] idpos; // identifier positions 2140 2141 static struct Replacement 2142 { 2143 size_t pos; // postion in original mangled string 2144 size_t respos; // postion in result string 2145 } 2146 Replacement [] replacements; 2147 2148 pure @safe: 2149 size_t positionInResult(size_t pos) scope 2150 { 2151 foreach_reverse (r; replacements) 2152 if (pos >= r.pos) 2153 return r.respos + pos - r.pos; 2154 return pos; 2155 } 2156 2157 alias Remangle = Demangle!(PrependHooks); 2158 2159 void flushPosition(ref Remangle d) scope 2160 { 2161 if (lastpos < d.pos) 2162 { 2163 result ~= d.buf[lastpos .. d.pos]; 2164 } 2165 else if (lastpos > d.pos) 2166 { 2167 // roll back to earlier position 2168 while (replacements.length > 0 && replacements[$-1].pos > d.pos) 2169 replacements = replacements[0 .. $-1]; 2170 2171 if (replacements.length > 0) 2172 result.length = replacements[$-1].respos + d.pos - replacements[$-1].pos; 2173 else 2174 result.length = d.pos; 2175 } 2176 } 2177 2178 bool parseLName(scope ref Remangle d) scope @trusted 2179 { 2180 flushPosition(d); 2181 2182 auto reslen = result.length; 2183 auto refpos = d.pos; 2184 if (d.front == 'Q') 2185 { 2186 size_t npos; 2187 { 2188 //scope(exit) result.length = reslen; // remove all intermediate additions 2189 // only support identifier back references 2190 d.popFront(); 2191 size_t n = d.decodeBackref(); 2192 if (!n || n > refpos) 2193 d.error("invalid back reference"); 2194 2195 auto savepos = d.pos; 2196 //scope(exit) d.pos = savepos; 2197 size_t srcpos = refpos - n; 2198 2199 auto idlen = d.decodeNumber(); 2200 if (d.pos + idlen > d.buf.length) 2201 d.error("invalid back reference"); 2202 auto id = d.buf[d.pos .. d.pos + idlen]; 2203 auto pid = id in idpos; 2204 if (!pid) 2205 d.error("invalid back reference"); 2206 npos = positionInResult(*pid); 2207 result.length = reslen; 2208 d.pos = savepos; 2209 } 2210 encodeBackref(reslen - npos); 2211 const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675 2212 replacements ~= Replacement(pos, result.length); 2213 } 2214 else 2215 { 2216 auto n = d.decodeNumber(); 2217 if (!n || n > d.buf.length || n > d.buf.length - d.pos) 2218 d.error("LName too shot or too long"); 2219 auto id = d.buf[d.pos .. d.pos + n]; 2220 d.pos += n; 2221 if (auto pid = id in idpos) 2222 { 2223 size_t npos = positionInResult(*pid); 2224 result.length = reslen; 2225 encodeBackref(reslen - npos); 2226 const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675 2227 replacements ~= Replacement(pos, result.length); 2228 } 2229 else 2230 { 2231 idpos[id] = refpos; 2232 result ~= d.buf[refpos .. d.pos]; 2233 } 2234 } 2235 lastpos = d.pos; 2236 return true; 2237 } 2238 2239 char[] parseType( ref Remangle d, char[] name = null ) return scope 2240 { 2241 if (d.front != 'Q') 2242 return null; 2243 2244 flushPosition(d); 2245 2246 auto refPos = d.pos; 2247 d.popFront(); 2248 auto n = d.decodeBackref(); 2249 if (n == 0 || n > refPos) 2250 d.error("invalid back reference"); 2251 2252 size_t npos = positionInResult(refPos - n); 2253 size_t reslen = result.length; 2254 encodeBackref(reslen - npos); 2255 2256 lastpos = d.pos; 2257 return result[reslen .. $]; // anything but null 2258 } 2259 2260 void encodeBackref(size_t relpos) scope 2261 { 2262 result ~= 'Q'; 2263 enum base = 26; 2264 size_t div = 1; 2265 while (relpos >= div * base) 2266 div *= base; 2267 while (div >= base) 2268 { 2269 auto dig = (relpos / div); 2270 result ~= cast(char)('A' + dig); 2271 relpos -= dig * div; 2272 div /= base; 2273 } 2274 result ~= cast(char)('a' + relpos); 2275 } 2276 } 2277 2278 auto d = Demangle!(PrependHooks)(mangled, null); 2279 d.hooks = PrependHooks(); 2280 d.mute = true; // no demangled output 2281 // try 2282 // { 2283 d.parseMangledName(); 2284 if (d.hooks.lastpos < d.pos) 2285 d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos]; 2286 return d.hooks.result; 2287 // } 2288 // catch (Exception) 2289 // { 2290 // // overflow exception cannot occur 2291 // return mangled.dup; 2292 // } 2293 } 2294 2295 /** 2296 * Mangles a D symbol. 2297 * 2298 * Params: 2299 * T = The type of the symbol. 2300 * fqn = The fully qualified name of the symbol. 2301 * dst = An optional destination buffer. 2302 * 2303 * Returns: 2304 * The mangled name for a symbols of type T and the given fully 2305 * qualified name. 2306 */ 2307 char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow 2308 { 2309 import core.internal.string : numDigits, unsignedToTempString; 2310 2311 static struct DotSplitter 2312 { 2313 @safe pure nothrow: 2314 const(char)[] s; 2315 2316 @property bool empty() const { return !s.length; } 2317 2318 @property const(char)[] front() const return 2319 { 2320 immutable i = indexOfDot(); 2321 return i == -1 ? s[0 .. $] : s[0 .. i]; 2322 } 2323 2324 void popFront() scope 2325 { 2326 immutable i = indexOfDot(); 2327 s = i == -1 ? s[$ .. $] : s[i+1 .. $]; 2328 } 2329 2330 private ptrdiff_t indexOfDot() const scope 2331 { 2332 foreach (i, c; s) if (c == '.') return i; 2333 return -1; 2334 } 2335 } 2336 2337 size_t len = "_D".length; 2338 foreach (comp; DotSplitter(fqn)) 2339 len += numDigits(comp.length) + comp.length; 2340 len += T.mangleof.length; 2341 if (dst.length < len) dst.length = len; 2342 2343 size_t i = "_D".length; 2344 dst[0 .. i] = "_D"; 2345 foreach (comp; DotSplitter(fqn)) 2346 { 2347 const ndigits = numDigits(comp.length); 2348 unsignedToTempString(comp.length, dst[i .. i + ndigits]); 2349 i += ndigits; 2350 dst[i .. i + comp.length] = comp[]; 2351 i += comp.length; 2352 } 2353 dst[i .. i + T.mangleof.length] = T.mangleof[]; 2354 i += T.mangleof.length; 2355 2356 static if (hasTypeBackRef) 2357 return reencodeMangled(dst[0 .. i]); 2358 else 2359 return dst[0 .. i]; 2360 } 2361 2362 2363 /// 2364 @safe pure nothrow unittest 2365 { 2366 assert(mangle!int("a.b") == "_D1a1bi"); 2367 assert(mangle!(char[])("test.foo") == "_D4test3fooAa"); 2368 assert(mangle!(int function(int))("a.b") == "_D1a1bPFiZi"); 2369 } 2370 2371 @safe pure nothrow unittest 2372 { 2373 static assert(mangle!int("a.b") == "_D1a1bi"); 2374 2375 auto buf = new char[](10); 2376 buf = mangle!int("a.b", buf); 2377 assert(buf == "_D1a1bi"); 2378 buf = mangle!(char[])("test.foo", buf); 2379 assert(buf == "_D4test3fooAa"); 2380 buf = mangle!(real delegate(int))("modµ.dg"); 2381 assert(buf == "_D5modµ2dgDFiZe", buf); 2382 } 2383 2384 2385 /** 2386 * Mangles a D function. 2387 * 2388 * Params: 2389 * T = function pointer type. 2390 * fqn = The fully qualified name of the symbol. 2391 * dst = An optional destination buffer. 2392 * 2393 * Returns: 2394 * The mangled name for a function with function pointer type T and 2395 * the given fully qualified name. 2396 */ 2397 char[] mangleFunc(T:FT*, FT)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow if (is(FT == function)) 2398 { 2399 static if (isExternD!FT) 2400 { 2401 return mangle!FT(fqn, dst); 2402 } 2403 else static if (hasPlainMangling!FT) 2404 { 2405 dst.length = fqn.length; 2406 dst[] = fqn[]; 2407 return dst; 2408 } 2409 else static if (isExternCPP!FT) 2410 { 2411 static assert(0, "Can't mangle extern(C++) functions."); 2412 } 2413 else 2414 { 2415 static assert(0, "Can't mangle function with unknown linkage ("~FT.stringof~")."); 2416 } 2417 } 2418 2419 private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi"; 2420 2421 private template isExternD(FT) if (is(FT == function)) 2422 { 2423 enum isExternD = __traits(getLinkage, FT) == "D"; 2424 } 2425 2426 private template isExternCPP(FT) if (is(FT == function)) 2427 { 2428 enum isExternCPP = __traits(getLinkage, FT) == "C++"; 2429 } 2430 2431 private template hasPlainMangling(FT) if (is(FT == function)) 2432 { 2433 enum lnk = __traits(getLinkage, FT); 2434 // C || Windows 2435 enum hasPlainMangling = lnk == "C" || lnk == "Windows" || lnk == "System"; 2436 } 2437 2438 enum string cPrefix = "_"; 2439 2440 private struct ManglingFlagInfo 2441 { 2442 /// The flag value to use 2443 ushort flag; 2444 2445 /// Human-readable representation 2446 string value; 2447 } 2448 2449 private enum TypeCtor : ushort { 2450 None = 0, 2451 //// 'x' 2452 Const = (1 << 1), 2453 /// 'y' 2454 Immutable = (1 << 2), 2455 /// 'O' 2456 Shared = (1 << 3), 2457 /// 2458 InOut = (1 << 4), 2459 } 2460 2461 private immutable ManglingFlagInfo[] typeCtors = [ 2462 ManglingFlagInfo(TypeCtor.Immutable, "immutable"), 2463 ManglingFlagInfo(TypeCtor.Shared, "shared"), 2464 ManglingFlagInfo(TypeCtor.InOut, "inout"), 2465 ManglingFlagInfo(TypeCtor.Const, "const"), 2466 ]; 2467 2468 private enum FuncAttributes : ushort { 2469 None = 0, 2470 //// 'a' 2471 Pure = (1 << 1), 2472 //// 'b' 2473 Nothrow = (1 << 2), 2474 //// 'c' 2475 Ref = (1 << 3), 2476 //// 'd' 2477 Property = (1 << 4), 2478 //// 'e' 2479 Trusted = (1 << 5), 2480 //// 'f' 2481 Safe = (1 << 6), 2482 //// 'i' 2483 NoGC = (1 << 7), 2484 //// 'j' 2485 Return = (1 << 8), 2486 //// 'l' 2487 Scope = (1 << 9), 2488 //// 'm' 2489 Live = (1 << 10), 2490 2491 /// Their order matter 2492 ReturnScope = (1 << 11), 2493 ScopeReturn = (1 << 12), 2494 } 2495 2496 // The order in which we process is the same as in compiler/dmd/src/dmangle.d 2497 private immutable ManglingFlagInfo[] funcAttrs = [ 2498 ManglingFlagInfo(FuncAttributes.Pure, "pure"), 2499 ManglingFlagInfo(FuncAttributes.Nothrow, "nothrow"), 2500 ManglingFlagInfo(FuncAttributes.Ref, "ref"), 2501 ManglingFlagInfo(FuncAttributes.Property, "@property"), 2502 ManglingFlagInfo(FuncAttributes.NoGC, "@nogc"), 2503 2504 ManglingFlagInfo(FuncAttributes.ReturnScope, "return scope"), 2505 ManglingFlagInfo(FuncAttributes.ScopeReturn, "scope return"), 2506 2507 ManglingFlagInfo(FuncAttributes.Return, "return"), 2508 ManglingFlagInfo(FuncAttributes.Scope, "scope"), 2509 2510 ManglingFlagInfo(FuncAttributes.Live, "@live"), 2511 ManglingFlagInfo(FuncAttributes.Trusted, "@trusted"), 2512 ManglingFlagInfo(FuncAttributes.Safe, "@safe"), 2513 ]; 2514 2515 private string toStringConsume (immutable ManglingFlagInfo[] infos, ref ushort base) 2516 @safe pure nothrow @nogc 2517 { 2518 foreach (const ref info; infos) 2519 { 2520 if ((base & info.flag) == info.flag) 2521 { 2522 base &= ~info.flag; 2523 return info.value; 2524 } 2525 } 2526 return null; 2527 } 2528 2529 private shared CXX_DEMANGLER __cxa_demangle; 2530 2531 /** 2532 * Demangles C++ mangled names. If it is not a C++ mangled name, it 2533 * returns its argument name. 2534 * 2535 * Params: 2536 * buf = The string to demangle. 2537 * __cxa_demangle = C++ demangler 2538 * dst = An optional destination buffer. 2539 * 2540 * Returns: 2541 * The demangled name or the original string if the name is not a mangled 2542 * C++ name. 2543 */ 2544 private char[] demangleCXX(return scope const(char)[] buf, CXX_DEMANGLER __cxa_demangle, return scope char[] dst = null,) nothrow pure @trusted 2545 { 2546 assert(false, "Not implemented"); 2547 } 2548 2549 /** 2550 * Error handling through Exceptions 2551 * 2552 * The following types / functions are only used in this module, 2553 * hence why the functions are `@trusted`. 2554 * To make things `@nogc`, default-initialized instances are thrown. 2555 */ 2556 private class ParseException : Exception 2557 { 2558 public this(string msg) @safe pure nothrow 2559 { 2560 super(msg); 2561 } 2562 } 2563 2564 /// Ditto 2565 private class OverflowException : Exception 2566 { 2567 public this(string msg) @safe pure nothrow 2568 { 2569 super(msg); 2570 } 2571 } 2572 2573 /// Ditto 2574 private noreturn error(string msg = "Invalid symbol") @trusted pure 2575 { 2576 2577 version (DigitalMars) pragma(inline, false); // tame dmd inliner 2578 assert(0, msg); 2579 // //throw new ParseException( msg ); 2580 // debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); 2581 // throw __ctfe ? new ParseException(msg) 2582 // : cast(ParseException) __traits(initSymbol, ParseException).ptr; 2583 } 2584 2585 /// Ditto 2586 private noreturn overflow(string msg = "Buffer overflow") @trusted pure 2587 { 2588 version (DigitalMars) pragma(inline, false); // tame dmd inliner 2589 assert(0, msg); 2590 // //throw new OverflowException( msg ); 2591 // debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); 2592 // throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr; 2593 } 2594 2595 private struct Buffer 2596 { 2597 enum size_t minSize = 4000; 2598 2599 @safe pure: 2600 2601 private char[] dst; 2602 private size_t len; 2603 2604 public alias opDollar = len; 2605 2606 public size_t length () const scope @safe pure nothrow @nogc 2607 { 2608 return this.len; 2609 } 2610 2611 public inout(char)[] opSlice (size_t from, size_t to) 2612 inout return scope @safe pure nothrow @nogc 2613 { 2614 assert(from <= to); 2615 assert(to <= len); 2616 return this.dst[from .. to]; 2617 } 2618 2619 static bool contains(scope const(char)[] a, scope const(char)[] b) @trusted 2620 { 2621 if (a.length && b.length) 2622 { 2623 auto bend = b.ptr + b.length; 2624 auto aend = a.ptr + a.length; 2625 return a.ptr <= b.ptr && bend <= aend; 2626 } 2627 return false; 2628 } 2629 2630 char[] copyInput(scope const(char)[] buf) 2631 return scope nothrow 2632 { 2633 if (dst.length < buf.length) 2634 dst.length = buf.length; 2635 char[] r = dst[0 .. buf.length]; 2636 r[] = buf[]; 2637 return r; 2638 } 2639 2640 // move val to the end of the dst buffer 2641 char[] shift(scope const(char)[] val) return scope 2642 { 2643 version (DigitalMars) pragma(inline, false); // tame dmd inliner 2644 2645 if (val.length) 2646 { 2647 assert( contains( dst[0 .. len], val ) ); 2648 debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr ); 2649 2650 if (len + val.length > dst.length) 2651 overflow(); 2652 size_t v = &val[0] - &dst[0]; 2653 dst[len .. len + val.length] = val[]; 2654 for (size_t p = v; p < len; p++) 2655 dst[p] = dst[p + val.length]; 2656 2657 return dst[len - val.length .. len]; 2658 } 2659 return null; 2660 } 2661 2662 // remove val from dst buffer 2663 void remove(scope const(char)[] val) scope 2664 { 2665 version (DigitalMars) pragma(inline, false); // tame dmd inliner 2666 2667 if ( val.length ) 2668 { 2669 assert( contains( dst[0 .. len], val ) ); 2670 debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr ); 2671 size_t v = &val[0] - &dst[0]; 2672 assert( len >= val.length && len <= dst.length ); 2673 len -= val.length; 2674 for (size_t p = v; p < len; p++) 2675 dst[p] = dst[p + val.length]; 2676 } 2677 } 2678 2679 char[] append(scope const(char)[] val) return scope 2680 { 2681 version (DigitalMars) pragma(inline, false); // tame dmd inliner 2682 2683 if (val.length) 2684 { 2685 if ( !dst.length ) 2686 dst.length = minSize; 2687 assert( !contains( dst[0 .. len], val ) ); 2688 debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr ); 2689 2690 if ( dst.length - len >= val.length && &dst[len] == &val[0] ) 2691 { 2692 // data is already in place 2693 auto t = dst[len .. len + val.length]; 2694 len += val.length; 2695 return t; 2696 } 2697 if ( dst.length - len >= val.length ) 2698 { 2699 dst[len .. len + val.length] = val[]; 2700 auto t = dst[len .. len + val.length]; 2701 len += val.length; 2702 return t; 2703 } 2704 overflow(); 2705 } 2706 return null; 2707 } 2708 } 2709 2710 2711 extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name, 2712 char* output_buffer, 2713 size_t* length, 2714 int* status) nothrow pure @trusted;