1 /** 2 * Copy from druntime available module buth with modifications allowing it's usage in @nogc. 3 * 4 * Warning: This is currently used in backtrace printing in which case buffer to demangle into is a 5 * slice to static array (1024B). be aware that this @nogc variant is altered in a way, that it just 6 * asserts in case of more data is needed. Backtrace printing is handled this way in druntime (as 7 * it'll be a problem when demangle'll resize static array slice), so it should be ok for us too. 8 * Just be carefull about that. 9 * 10 * All modifications to the original are noted in comments with 'CHANGE:'. 11 * 12 * See: https://github.com/dlang/druntime/blob/master/src/core/demangle.d 13 * Last revision from: d2d49ab4930e1ffd3ece6e5a6ea7767a01d5e077 14 */ 15 module bc.core.demangle; 16 17 version (D_BetterC) {} 18 else: 19 20 import core.exception : onOutOfMemoryErrorNoGC; 21 22 struct NoHooks {} 23 24 // NOTE: Copy from https://github.com/dlang/druntime/blob/master/src/core/demangle.d (commit 99534d2595aa8a4851430de3c276308b829236b7) 25 struct Demangle(Hooks = NoHooks) 26 { 27 // NOTE: This implementation currently only works with mangled function 28 // names as they exist in an object file. Type names mangled via 29 // the .mangleof property are effectively incomplete as far as the 30 // ABI is concerned and so are not considered to be mangled symbol 31 // names. 32 33 // NOTE: This implementation builds the demangled buffer in place by 34 // writing data as it is decoded and then rearranging it later as 35 // needed. In practice this results in very little data movement, 36 // and the performance cost is more than offset by the gain from 37 // not allocating dynamic memory to assemble the name piecemeal. 38 // 39 // If the destination buffer is too small, parsing will restart 40 // with a larger buffer. Since this generally means only one 41 // allocation during the course of a parsing run, this is still 42 // faster than assembling the result piecemeal. 43 44 pure @safe @nogc: // CHANGE: added @nogc 45 enum AddType { no, yes } 46 47 48 this( return const(char)[] buf_, return char[] dst_ = null ) 49 { 50 this( buf_, AddType.yes, dst_ ); 51 } 52 53 54 this( return const(char)[] buf_, AddType addType_, return char[] dst_ = null ) 55 { 56 buf = buf_; 57 addType = addType_; 58 dst = dst_; 59 } 60 61 62 enum size_t minBufSize = 4000; 63 64 65 const(char)[] buf = null; 66 char[] dst = null; 67 size_t pos = 0; 68 size_t len = 0; 69 size_t brp = 0; // current back reference pos 70 AddType addType = AddType.yes; 71 bool mute = false; 72 Hooks hooks; 73 74 static class ParseException : Exception 75 { 76 @safe pure nothrow this( string msg ) 77 { 78 super( msg ); 79 } 80 } 81 82 83 static class OverflowException : Exception 84 { 85 @safe pure nothrow this( string msg ) 86 { 87 super( msg ); 88 } 89 } 90 91 92 static void error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */ 93 { 94 pragma(inline, false); // tame dmd inliner 95 96 //throw new ParseException( msg ); 97 debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); 98 throw cast(ParseException) cast(void*) typeid(ParseException).initializer; // CHANGE: not used in ctfe 99 } 100 101 102 static void overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */ 103 { 104 pragma(inline, false); // tame dmd inliner 105 106 //throw new OverflowException( msg ); 107 debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr ); 108 throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer; 109 } 110 111 112 ////////////////////////////////////////////////////////////////////////// 113 // Type Testing and Conversion 114 ////////////////////////////////////////////////////////////////////////// 115 116 117 static bool isAlpha( char val ) 118 { 119 return ('a' <= val && 'z' >= val) || 120 ('A' <= val && 'Z' >= val) || 121 (0x80 & val); // treat all unicode as alphabetic 122 } 123 124 125 static bool isDigit( char val ) 126 { 127 return '0' <= val && '9' >= val; 128 } 129 130 131 static bool isHexDigit( char val ) 132 { 133 return ('0' <= val && '9' >= val) || 134 ('a' <= val && 'f' >= val) || 135 ('A' <= val && 'F' >= val); 136 } 137 138 139 static ubyte ascii2hex( char val ) 140 { 141 if (val >= 'a' && val <= 'f') 142 return cast(ubyte)(val - 'a' + 10); 143 if (val >= 'A' && val <= 'F') 144 return cast(ubyte)(val - 'A' + 10); 145 if (val >= '0' && val <= '9') 146 return cast(ubyte)(val - '0'); 147 error(); 148 return 0; 149 } 150 151 152 ////////////////////////////////////////////////////////////////////////// 153 // Data Output 154 ////////////////////////////////////////////////////////////////////////// 155 156 157 static bool contains( const(char)[] a, const(char)[] b ) @trusted 158 { 159 if (a.length && b.length) 160 { 161 auto bend = b.ptr + b.length; 162 auto aend = a.ptr + a.length; 163 return a.ptr <= b.ptr && bend <= aend; 164 } 165 return false; 166 } 167 168 169 // move val to the end of the dst buffer 170 char[] shift( const(char)[] val ) 171 { 172 pragma(inline, false); // tame dmd inliner 173 174 if ( val.length && !mute ) 175 { 176 assert( contains( dst[0 .. len], val ) ); 177 debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr ); 178 179 if (len + val.length > dst.length) 180 overflow(); 181 size_t v = &val[0] - &dst[0]; 182 dst[len .. len + val.length] = val[]; 183 for (size_t p = v; p < len; p++) 184 dst[p] = dst[p + val.length]; 185 186 return dst[len - val.length .. len]; 187 } 188 return null; 189 } 190 191 // remove val from dst buffer 192 void remove( const(char)[] val ) 193 { 194 pragma(inline, false); // tame dmd inliner 195 196 if ( val.length ) 197 { 198 assert( contains( dst[0 .. len], val ) ); 199 debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr ); 200 size_t v = &val[0] - &dst[0]; 201 assert( len >= val.length && len <= dst.length ); 202 len -= val.length; 203 for (size_t p = v; p < len; p++) 204 dst[p] = dst[p + val.length]; 205 } 206 } 207 208 char[] append( const(char)[] val ) return scope 209 { 210 pragma(inline, false); // tame dmd inliner 211 212 if ( val.length && !mute ) 213 { 214 if ( !dst.length ) 215 // dst.length = minBufSize; 216 assert(0, "out of range"); // CHANGE: can't realloc slice of the provided static array anyway 217 assert( !contains( dst[0 .. len], val ) ); 218 debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr ); 219 220 if ( dst.length - len >= val.length && &dst[len] == &val[0] ) 221 { 222 // data is already in place 223 auto t = dst[len .. len + val.length]; 224 len += val.length; 225 return t; 226 } 227 if ( dst.length - len >= val.length ) 228 { 229 dst[len .. len + val.length] = val[]; 230 auto t = dst[len .. len + val.length]; 231 len += val.length; 232 return t; 233 } 234 overflow(); 235 } 236 return null; 237 } 238 239 void putComma(size_t n) 240 { 241 pragma(inline, false); 242 if (n) 243 put(", "); 244 } 245 246 char[] put(char c) return scope 247 { 248 char[1] val = c; 249 return put(val[]); 250 } 251 252 char[] put( scope const(char)[] val ) return scope 253 { 254 pragma(inline, false); // tame dmd inliner 255 256 if ( val.length ) 257 { 258 if ( !contains( dst[0 .. len], val ) ) 259 return append( val ); 260 return shift( val ); 261 } 262 return null; 263 } 264 265 266 void putAsHex( size_t val, int width = 0 ) 267 { 268 import core.internal.string; 269 270 UnsignedStringBuf buf = void; 271 272 static if (__VERSION__ >= 2094) auto s = unsignedToTempString!16(val, buf); 273 else auto s = unsignedToTempString(val, buf, 16); 274 int slen = cast(int)s.length; 275 if (slen < width) 276 { 277 foreach (i; slen .. width) 278 put('0'); 279 } 280 put(s); 281 } 282 283 284 void pad( const(char)[] val ) 285 { 286 if ( val.length ) 287 { 288 append( " " ); 289 put( val ); 290 } 291 } 292 293 294 // CHANGE: reworked 295 // void silent( void delegate() pure @safe @nogc dg ) 296 // { 297 // debug(trace) printf( "silent+\n" ); 298 // debug(trace) scope(success) printf( "silent-\n" ); 299 // auto n = len; dg(); len = n; 300 // } 301 302 303 ////////////////////////////////////////////////////////////////////////// 304 // Parsing Utility 305 ////////////////////////////////////////////////////////////////////////// 306 307 @property bool empty() 308 { 309 return pos >= buf.length; 310 } 311 312 @property char front() 313 { 314 if ( pos < buf.length ) 315 return buf[pos]; 316 return char.init; 317 } 318 319 char peek( size_t n ) 320 { 321 if ( pos + n < buf.length ) 322 return buf[pos + n]; 323 return char.init; 324 } 325 326 327 void test( char val ) 328 { 329 if ( val != front ) 330 error(); 331 } 332 333 334 void popFront() 335 { 336 if ( pos++ >= buf.length ) 337 error(); 338 } 339 340 341 void match( char val ) 342 { 343 test( val ); 344 popFront(); 345 } 346 347 348 void match( const(char)[] val ) 349 { 350 foreach (char e; val ) 351 { 352 test( e ); 353 popFront(); 354 } 355 } 356 357 358 void eat( char val ) 359 { 360 if ( val == front ) 361 popFront(); 362 } 363 364 bool isSymbolNameFront() 365 { 366 char val = front; 367 if ( isDigit( val ) || val == '_' ) 368 return true; 369 if ( val != 'Q' ) 370 return false; 371 372 // check the back reference encoding after 'Q' 373 val = peekBackref(); 374 return isDigit( val ); // identifier ref 375 } 376 377 // return the first character at the back reference 378 char peekBackref() 379 { 380 assert( front == 'Q' ); 381 auto n = decodeBackref!1(); 382 if (!n || n > pos) 383 error("invalid back reference"); 384 385 return buf[pos - n]; 386 } 387 388 size_t decodeBackref(size_t peekAt = 0)() 389 { 390 enum base = 26; 391 size_t n = 0; 392 for (size_t p; ; p++) 393 { 394 char t; 395 static if (peekAt > 0) 396 { 397 t = peek(peekAt + p); 398 } 399 else 400 { 401 t = front; 402 popFront(); 403 } 404 if (t < 'A' || t > 'Z') 405 { 406 if (t < 'a' || t > 'z') 407 error("invalid back reference"); 408 n = base * n + t - 'a'; 409 return n; 410 } 411 n = base * n + t - 'A'; 412 } 413 } 414 415 ////////////////////////////////////////////////////////////////////////// 416 // Parsing Implementation 417 ////////////////////////////////////////////////////////////////////////// 418 419 420 /* 421 Number: 422 Digit 423 Digit Number 424 */ 425 const(char)[] sliceNumber() return scope 426 { 427 debug(trace) printf( "sliceNumber+\n" ); 428 debug(trace) scope(success) printf( "sliceNumber-\n" ); 429 430 auto beg = pos; 431 432 while ( true ) 433 { 434 auto t = front; 435 if (t >= '0' && t <= '9') 436 popFront(); 437 else 438 return buf[beg .. pos]; 439 } 440 } 441 442 443 size_t decodeNumber() scope 444 { 445 debug(trace) printf( "decodeNumber+\n" ); 446 debug(trace) scope(success) printf( "decodeNumber-\n" ); 447 448 return decodeNumber( sliceNumber() ); 449 } 450 451 452 size_t decodeNumber( scope const(char)[] num ) scope 453 { 454 debug(trace) printf( "decodeNumber+\n" ); 455 debug(trace) scope(success) printf( "decodeNumber-\n" ); 456 457 size_t val = 0; 458 459 foreach ( c; num ) 460 { 461 import core.checkedint : mulu, addu; 462 463 bool overflow = false; 464 val = mulu(val, 10, overflow); 465 val = addu(val, c - '0', overflow); 466 if (overflow) 467 error(); 468 } 469 return val; 470 } 471 472 473 void parseReal() scope 474 { 475 debug(trace) printf( "parseReal+\n" ); 476 debug(trace) scope(success) printf( "parseReal-\n" ); 477 478 char[64] tbuf = void; 479 size_t tlen = 0; 480 real val = void; 481 482 if ( 'I' == front ) 483 { 484 match( "INF" ); 485 put( "real.infinity" ); 486 return; 487 } 488 if ( 'N' == front ) 489 { 490 popFront(); 491 if ( 'I' == front ) 492 { 493 match( "INF" ); 494 put( "-real.infinity" ); 495 return; 496 } 497 if ( 'A' == front ) 498 { 499 match( "AN" ); 500 put( "real.nan" ); 501 return; 502 } 503 tbuf[tlen++] = '-'; 504 } 505 506 tbuf[tlen++] = '0'; 507 tbuf[tlen++] = 'X'; 508 if ( !isHexDigit( front ) ) 509 error( "Expected hex digit" ); 510 tbuf[tlen++] = front; 511 tbuf[tlen++] = '.'; 512 popFront(); 513 514 while ( isHexDigit( front ) ) 515 { 516 tbuf[tlen++] = front; 517 popFront(); 518 } 519 match( 'P' ); 520 tbuf[tlen++] = 'p'; 521 if ( 'N' == front ) 522 { 523 tbuf[tlen++] = '-'; 524 popFront(); 525 } 526 else 527 { 528 tbuf[tlen++] = '+'; 529 } 530 while ( isDigit( front ) ) 531 { 532 tbuf[tlen++] = front; 533 popFront(); 534 } 535 536 tbuf[tlen] = 0; 537 debug(info) printf( "got (%s)\n", tbuf.ptr ); 538 pureReprintReal( tbuf[] ); 539 debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr ); 540 put( tbuf[0 .. tlen] ); 541 } 542 543 544 /* 545 LName: 546 Number Name 547 548 Name: 549 Namestart 550 Namestart Namechars 551 552 Namestart: 553 _ 554 Alpha 555 556 Namechar: 557 Namestart 558 Digit 559 560 Namechars: 561 Namechar 562 Namechar Namechars 563 */ 564 void parseLName() scope 565 { 566 debug(trace) printf( "parseLName+\n" ); 567 debug(trace) scope(success) printf( "parseLName-\n" ); 568 569 static if (__traits(hasMember, Hooks, "parseLName")) 570 if (hooks.parseLName(this)) 571 return; 572 573 if ( front == 'Q' ) 574 { 575 // back reference to LName 576 auto refPos = pos; 577 popFront(); 578 size_t n = decodeBackref(); 579 if ( !n || n > refPos ) 580 error( "Invalid LName back reference" ); 581 if ( !mute ) 582 { 583 auto savePos = pos; 584 scope(exit) pos = savePos; 585 pos = refPos - n; 586 parseLName(); 587 } 588 return; 589 } 590 auto n = decodeNumber(); 591 if ( n == 0 ) 592 { 593 put( "__anonymous" ); 594 return; 595 } 596 if ( n > buf.length || n > buf.length - pos ) 597 error( "LName must be at least 1 character" ); 598 if ( '_' != front && !isAlpha( front ) ) 599 error( "Invalid character in LName" ); 600 foreach (char e; buf[pos + 1 .. pos + n] ) 601 { 602 if ( '_' != e && !isAlpha( e ) && !isDigit( e ) ) 603 error( "Invalid character in LName" ); 604 } 605 606 put( buf[pos .. pos + n] ); 607 pos += n; 608 } 609 610 611 /* 612 Type: 613 Shared 614 Const 615 Immutable 616 Wild 617 TypeArray 618 TypeVector 619 TypeStaticArray 620 TypeAssocArray 621 TypePointer 622 TypeFunction 623 TypeIdent 624 TypeClass 625 TypeStruct 626 TypeEnum 627 TypeTypedef 628 TypeDelegate 629 TypeNone 630 TypeVoid 631 TypeByte 632 TypeUbyte 633 TypeShort 634 TypeUshort 635 TypeInt 636 TypeUint 637 TypeLong 638 TypeUlong 639 TypeCent 640 TypeUcent 641 TypeFloat 642 TypeDouble 643 TypeReal 644 TypeIfloat 645 TypeIdouble 646 TypeIreal 647 TypeCfloat 648 TypeCdouble 649 TypeCreal 650 TypeBool 651 TypeChar 652 TypeWchar 653 TypeDchar 654 TypeTuple 655 656 Shared: 657 O Type 658 659 Const: 660 x Type 661 662 Immutable: 663 y Type 664 665 Wild: 666 Ng Type 667 668 TypeArray: 669 A Type 670 671 TypeVector: 672 Nh Type 673 674 TypeStaticArray: 675 G Number Type 676 677 TypeAssocArray: 678 H Type Type 679 680 TypePointer: 681 P Type 682 683 TypeFunction: 684 CallConvention FuncAttrs Arguments ArgClose Type 685 686 TypeIdent: 687 I LName 688 689 TypeClass: 690 C LName 691 692 TypeStruct: 693 S LName 694 695 TypeEnum: 696 E LName 697 698 TypeTypedef: 699 T LName 700 701 TypeDelegate: 702 D TypeFunction 703 704 TypeNone: 705 n 706 707 TypeVoid: 708 v 709 710 TypeByte: 711 g 712 713 TypeUbyte: 714 h 715 716 TypeShort: 717 s 718 719 TypeUshort: 720 t 721 722 TypeInt: 723 i 724 725 TypeUint: 726 k 727 728 TypeLong: 729 l 730 731 TypeUlong: 732 m 733 734 TypeCent 735 zi 736 737 TypeUcent 738 zk 739 740 TypeFloat: 741 f 742 743 TypeDouble: 744 d 745 746 TypeReal: 747 e 748 749 TypeIfloat: 750 o 751 752 TypeIdouble: 753 p 754 755 TypeIreal: 756 j 757 758 TypeCfloat: 759 q 760 761 TypeCdouble: 762 r 763 764 TypeCreal: 765 c 766 767 TypeBool: 768 b 769 770 TypeChar: 771 a 772 773 TypeWchar: 774 u 775 776 TypeDchar: 777 w 778 779 TypeTuple: 780 B Number Arguments 781 */ 782 char[] parseType( char[] name = null ) return scope 783 { 784 static immutable string[23] primitives = [ 785 "char", // a 786 "bool", // b 787 "creal", // c 788 "double", // d 789 "real", // e 790 "float", // f 791 "byte", // g 792 "ubyte", // h 793 "int", // i 794 "ireal", // j 795 "uint", // k 796 "long", // l 797 "ulong", // m 798 null, // n 799 "ifloat", // o 800 "idouble", // p 801 "cfloat", // q 802 "cdouble", // r 803 "short", // s 804 "ushort", // t 805 "wchar", // u 806 "void", // v 807 "dchar", // w 808 ]; 809 810 static if (__traits(hasMember, Hooks, "parseType")) 811 if (auto n = hooks.parseType(this, name)) 812 return n; 813 814 debug(trace) printf( "parseType+\n" ); 815 debug(trace) scope(success) printf( "parseType-\n" ); 816 auto beg = len; 817 auto t = front; 818 819 char[] parseBackrefType(scope char[] delegate() pure @safe @nogc parseDg) pure @safe 820 { 821 if (pos == brp) 822 error("recursive back reference"); 823 auto refPos = pos; 824 popFront(); 825 auto n = decodeBackref(); 826 if (n == 0 || n > pos) 827 error("invalid back reference"); 828 if ( mute ) 829 return null; 830 auto savePos = pos; 831 auto saveBrp = brp; 832 scope(success) { pos = savePos; brp = saveBrp; } 833 pos = refPos - n; 834 brp = refPos; 835 auto ret = parseDg(); 836 return ret; 837 } 838 839 switch ( t ) 840 { 841 case 'Q': // Type back reference 842 return parseBackrefType( () @nogc => parseType( name ) ); 843 case 'O': // Shared (O Type) 844 popFront(); 845 put( "shared(" ); 846 parseType(); 847 put( ')' ); 848 pad( name ); 849 return dst[beg .. len]; 850 case 'x': // Const (x Type) 851 popFront(); 852 put( "const(" ); 853 parseType(); 854 put( ')' ); 855 pad( name ); 856 return dst[beg .. len]; 857 case 'y': // Immutable (y Type) 858 popFront(); 859 put( "immutable(" ); 860 parseType(); 861 put( ')' ); 862 pad( name ); 863 return dst[beg .. len]; 864 case 'N': 865 popFront(); 866 switch ( front ) 867 { 868 case 'g': // Wild (Ng Type) 869 popFront(); 870 // TODO: Anything needed here? 871 put( "inout(" ); 872 parseType(); 873 put( ')' ); 874 return dst[beg .. len]; 875 case 'h': // TypeVector (Nh Type) 876 popFront(); 877 put( "__vector(" ); 878 parseType(); 879 put( ')' ); 880 return dst[beg .. len]; 881 default: 882 error(); 883 assert( 0 ); 884 } 885 case 'A': // TypeArray (A Type) 886 popFront(); 887 parseType(); 888 put( "[]" ); 889 pad( name ); 890 return dst[beg .. len]; 891 case 'G': // TypeStaticArray (G Number Type) 892 popFront(); 893 auto num = sliceNumber(); 894 parseType(); 895 put( '[' ); 896 put( num ); 897 put( ']' ); 898 pad( name ); 899 return dst[beg .. len]; 900 case 'H': // TypeAssocArray (H Type Type) 901 popFront(); 902 // skip t1 903 auto tx = parseType(); 904 parseType(); 905 put( '[' ); 906 put( tx ); 907 put( ']' ); 908 pad( name ); 909 return dst[beg .. len]; 910 case 'P': // TypePointer (P Type) 911 popFront(); 912 parseType(); 913 put( '*' ); 914 pad( name ); 915 return dst[beg .. len]; 916 case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction 917 return parseTypeFunction( name ); 918 case 'C': // TypeClass (C LName) 919 case 'S': // TypeStruct (S LName) 920 case 'E': // TypeEnum (E LName) 921 case 'T': // TypeTypedef (T LName) 922 popFront(); 923 parseQualifiedName(); 924 pad( name ); 925 return dst[beg .. len]; 926 case 'D': // TypeDelegate (D TypeFunction) 927 popFront(); 928 auto modbeg = len; 929 parseModifier(); 930 auto modend = len; 931 if ( front == 'Q' ) 932 parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) ); 933 else 934 parseTypeFunction( name, IsDelegate.yes ); 935 if (modend > modbeg) 936 { 937 // move modifiers behind the function arguments 938 shift(dst[modend-1 .. modend]); // trailing space 939 shift(dst[modbeg .. modend-1]); 940 } 941 return dst[beg .. len]; 942 case 'n': // TypeNone (n) 943 popFront(); 944 // TODO: Anything needed here? 945 return dst[beg .. len]; 946 case 'B': // TypeTuple (B Number Arguments) 947 popFront(); 948 // TODO: Handle this. 949 return dst[beg .. len]; 950 case 'Z': // Internal symbol 951 // This 'type' is used for untyped internal symbols, i.e.: 952 // __array 953 // __init 954 // __vtbl 955 // __Class 956 // __Interface 957 // __ModuleInfo 958 popFront(); 959 return dst[beg .. len]; 960 default: 961 if (t >= 'a' && t <= 'w') 962 { 963 popFront(); 964 put( primitives[cast(size_t)(t - 'a')] ); 965 pad( name ); 966 return dst[beg .. len]; 967 } 968 else if (t == 'z') 969 { 970 popFront(); 971 switch ( front ) 972 { 973 case 'i': 974 popFront(); 975 put( "cent" ); 976 pad( name ); 977 return dst[beg .. len]; 978 case 'k': 979 popFront(); 980 put( "ucent" ); 981 pad( name ); 982 return dst[beg .. len]; 983 default: 984 error(); 985 assert( 0 ); 986 } 987 } 988 error(); 989 return null; 990 } 991 } 992 993 994 /* 995 TypeFunction: 996 CallConvention FuncAttrs Arguments ArgClose Type 997 998 CallConvention: 999 F // D 1000 U // C 1001 W // Windows 1002 V // Pascal 1003 R // C++ 1004 1005 FuncAttrs: 1006 FuncAttr 1007 FuncAttr FuncAttrs 1008 1009 FuncAttr: 1010 empty 1011 FuncAttrPure 1012 FuncAttrNothrow 1013 FuncAttrProperty 1014 FuncAttrRef 1015 FuncAttrReturn 1016 FuncAttrScope 1017 FuncAttrTrusted 1018 FuncAttrSafe 1019 1020 FuncAttrPure: 1021 Na 1022 1023 FuncAttrNothrow: 1024 Nb 1025 1026 FuncAttrRef: 1027 Nc 1028 1029 FuncAttrProperty: 1030 Nd 1031 1032 FuncAttrTrusted: 1033 Ne 1034 1035 FuncAttrSafe: 1036 Nf 1037 1038 FuncAttrNogc: 1039 Ni 1040 1041 FuncAttrReturn: 1042 Nj 1043 1044 FuncAttrScope: 1045 Nl 1046 1047 Arguments: 1048 Argument 1049 Argument Arguments 1050 1051 Argument: 1052 Argument2 1053 M Argument2 // scope 1054 1055 Argument2: 1056 Type 1057 J Type // out 1058 K Type // ref 1059 L Type // lazy 1060 1061 ArgClose 1062 X // variadic T t,...) style 1063 Y // variadic T t...) style 1064 Z // not variadic 1065 */ 1066 void parseCallConvention() 1067 { 1068 // CallConvention 1069 switch ( front ) 1070 { 1071 case 'F': // D 1072 popFront(); 1073 break; 1074 case 'U': // C 1075 popFront(); 1076 put( "extern (C) " ); 1077 break; 1078 case 'W': // Windows 1079 popFront(); 1080 put( "extern (Windows) " ); 1081 break; 1082 case 'V': // Pascal 1083 popFront(); 1084 put( "extern (Pascal) " ); 1085 break; 1086 case 'R': // C++ 1087 popFront(); 1088 put( "extern (C++) " ); 1089 break; 1090 default: 1091 error(); 1092 } 1093 } 1094 1095 void parseModifier() 1096 { 1097 switch ( front ) 1098 { 1099 case 'y': 1100 popFront(); 1101 put( "immutable " ); 1102 break; 1103 case 'O': 1104 popFront(); 1105 put( "shared " ); 1106 if ( front == 'x' ) 1107 goto case 'x'; 1108 if ( front == 'N' ) 1109 goto case 'N'; 1110 break; 1111 case 'N': 1112 if ( peek( 1 ) != 'g' ) 1113 break; 1114 popFront(); 1115 popFront(); 1116 put( "inout " ); 1117 if ( front == 'x' ) 1118 goto case 'x'; 1119 break; 1120 case 'x': 1121 popFront(); 1122 put( "const " ); 1123 break; 1124 default: break; 1125 } 1126 } 1127 1128 void parseFuncAttr() 1129 { 1130 // FuncAttrs 1131 breakFuncAttrs: 1132 while ('N' == front) 1133 { 1134 popFront(); 1135 switch ( front ) 1136 { 1137 case 'a': // FuncAttrPure 1138 popFront(); 1139 put( "pure " ); 1140 continue; 1141 case 'b': // FuncAttrNoThrow 1142 popFront(); 1143 put( "nothrow " ); 1144 continue; 1145 case 'c': // FuncAttrRef 1146 popFront(); 1147 put( "ref " ); 1148 continue; 1149 case 'd': // FuncAttrProperty 1150 popFront(); 1151 put( "@property " ); 1152 continue; 1153 case 'e': // FuncAttrTrusted 1154 popFront(); 1155 put( "@trusted " ); 1156 continue; 1157 case 'f': // FuncAttrSafe 1158 popFront(); 1159 put( "@safe " ); 1160 continue; 1161 case 'g': 1162 case 'h': 1163 case 'k': 1164 // NOTE: The inout parameter type is represented as "Ng". 1165 // The vector parameter type is represented as "Nh". 1166 // The return parameter type is represented as "Nk". 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 if ( 'M' == front ) 1218 { 1219 popFront(); 1220 put( "scope " ); 1221 } 1222 if ( 'N' == front ) 1223 { 1224 popFront(); 1225 if ( 'k' == front ) // Return (Nk Parameter2) 1226 { 1227 popFront(); 1228 put( "return " ); 1229 } 1230 else 1231 pos--; 1232 } 1233 switch ( front ) 1234 { 1235 case 'I': // in (I Type) 1236 popFront(); 1237 put("in "); 1238 if (front == 'K') 1239 goto case; 1240 parseType(); 1241 continue; 1242 case 'K': // ref (K Type) 1243 popFront(); 1244 put( "ref " ); 1245 parseType(); 1246 continue; 1247 case 'J': // out (J Type) 1248 popFront(); 1249 put( "out " ); 1250 parseType(); 1251 continue; 1252 case 'L': // lazy (L Type) 1253 popFront(); 1254 put( "lazy " ); 1255 parseType(); 1256 continue; 1257 default: 1258 parseType(); 1259 } 1260 } 1261 } 1262 1263 enum IsDelegate { no, yes } 1264 1265 /* 1266 TypeFunction: 1267 CallConvention FuncAttrs Arguments ArgClose Type 1268 */ 1269 char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope 1270 { 1271 debug(trace) printf( "parseTypeFunction+\n" ); 1272 debug(trace) scope(success) printf( "parseTypeFunction-\n" ); 1273 auto beg = len; 1274 1275 parseCallConvention(); 1276 auto attrbeg = len; 1277 parseFuncAttr(); 1278 1279 auto argbeg = len; 1280 put( '(' ); 1281 parseFuncArguments(); 1282 put( ')' ); 1283 if (attrbeg < argbeg) 1284 { 1285 // move function attributes behind arguments 1286 shift( dst[argbeg - 1 .. argbeg] ); // trailing space 1287 shift( dst[attrbeg .. argbeg - 1] ); // attributes 1288 argbeg = attrbeg; 1289 } 1290 auto retbeg = len; 1291 parseType(); 1292 put( ' ' ); 1293 // append name/delegate/function 1294 if ( name.length ) 1295 { 1296 if ( !contains( dst[0 .. len], name ) ) 1297 put( name ); 1298 else if ( shift( name ).ptr != name.ptr ) 1299 { 1300 argbeg -= name.length; 1301 retbeg -= name.length; 1302 } 1303 } 1304 else if ( IsDelegate.yes == isdg ) 1305 put( "delegate" ); 1306 else 1307 put( "function" ); 1308 // move arguments and attributes behind name 1309 shift( dst[argbeg .. retbeg] ); 1310 return dst[beg..len]; 1311 } 1312 1313 static bool isCallConvention( char ch ) 1314 { 1315 switch ( ch ) 1316 { 1317 case 'F', 'U', 'V', 'W', 'R': 1318 return true; 1319 default: 1320 return false; 1321 } 1322 } 1323 1324 /* 1325 Value: 1326 n 1327 Number 1328 i Number 1329 N Number 1330 e HexFloat 1331 c HexFloat c HexFloat 1332 A Number Value... 1333 1334 HexFloat: 1335 NAN 1336 INF 1337 NINF 1338 N HexDigits P Exponent 1339 HexDigits P Exponent 1340 1341 Exponent: 1342 N Number 1343 Number 1344 1345 HexDigits: 1346 HexDigit 1347 HexDigit HexDigits 1348 1349 HexDigit: 1350 Digit 1351 A 1352 B 1353 C 1354 D 1355 E 1356 F 1357 */ 1358 void parseValue(scope char[] name = null, char type = '\0' ) scope 1359 { 1360 debug(trace) printf( "parseValue+\n" ); 1361 debug(trace) scope(success) printf( "parseValue-\n" ); 1362 1363 // printf( "*** %c\n", front ); 1364 switch ( front ) 1365 { 1366 case 'n': 1367 popFront(); 1368 put( "null" ); 1369 return; 1370 case 'i': 1371 popFront(); 1372 if ( '0' > front || '9' < front ) 1373 error( "Number expected" ); 1374 goto case; 1375 case '0': .. case '9': 1376 parseIntegerValue( name, type ); 1377 return; 1378 case 'N': 1379 popFront(); 1380 put( '-' ); 1381 parseIntegerValue( name, type ); 1382 return; 1383 case 'e': 1384 popFront(); 1385 parseReal(); 1386 return; 1387 case 'c': 1388 popFront(); 1389 parseReal(); 1390 put( '+' ); 1391 match( 'c' ); 1392 parseReal(); 1393 put( 'i' ); 1394 return; 1395 case 'a': case 'w': case 'd': 1396 char t = front; 1397 popFront(); 1398 auto n = decodeNumber(); 1399 match( '_' ); 1400 put( '"' ); 1401 foreach (i; 0..n) 1402 { 1403 auto a = ascii2hex( front ); popFront(); 1404 auto b = ascii2hex( front ); popFront(); 1405 auto v = cast(char)((a << 4) | b); 1406 if (' ' <= v && v <= '~') // ASCII printable 1407 { 1408 put(v); 1409 } 1410 else 1411 { 1412 put("\\x"); 1413 putAsHex(v, 2); 1414 } 1415 } 1416 put( '"' ); 1417 if ( 'a' != t ) 1418 put(t); 1419 return; 1420 case 'A': 1421 // NOTE: This is kind of a hack. An associative array literal 1422 // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type 1423 // is "Hii" and the value is "A2i1i2i3i4". Thus the only 1424 // way to determine that this is an AA value rather than an 1425 // array value is for the caller to supply the type char. 1426 // Hopefully, this will change so that the value is 1427 // "H2i1i2i3i4", rendering this unnecesary. 1428 if ( 'H' == type ) 1429 goto LassocArray; 1430 // A Number Value... 1431 // An array literal. Value is repeated Number times. 1432 popFront(); 1433 put( '[' ); 1434 auto n = decodeNumber(); 1435 foreach ( i; 0 .. n ) 1436 { 1437 putComma(i); 1438 parseValue(); 1439 } 1440 put( ']' ); 1441 return; 1442 case 'H': 1443 LassocArray: 1444 // H Number Value... 1445 // An associative array literal. Value is repeated 2*Number times. 1446 popFront(); 1447 put( '[' ); 1448 auto n = decodeNumber(); 1449 foreach ( i; 0 .. n ) 1450 { 1451 putComma(i); 1452 parseValue(); 1453 put(':'); 1454 parseValue(); 1455 } 1456 put( ']' ); 1457 return; 1458 case 'S': 1459 // S Number Value... 1460 // A struct literal. Value is repeated Number times. 1461 popFront(); 1462 if ( name.length ) 1463 put( name ); 1464 put( '(' ); 1465 auto n = decodeNumber(); 1466 foreach ( i; 0 .. n ) 1467 { 1468 putComma(i); 1469 parseValue(); 1470 } 1471 put( ')' ); 1472 return; 1473 default: 1474 error(); 1475 } 1476 } 1477 1478 1479 void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope 1480 { 1481 debug(trace) printf( "parseIntegerValue+\n" ); 1482 debug(trace) scope(success) printf( "parseIntegerValue-\n" ); 1483 1484 switch ( type ) 1485 { 1486 case 'a': // char 1487 case 'u': // wchar 1488 case 'w': // dchar 1489 { 1490 auto val = sliceNumber(); 1491 auto num = decodeNumber( val ); 1492 1493 switch ( num ) 1494 { 1495 case '\'': 1496 put( "'\\''" ); 1497 return; 1498 // \", \? 1499 case '\\': 1500 put( "'\\\\'" ); 1501 return; 1502 case '\a': 1503 put( "'\\a'" ); 1504 return; 1505 case '\b': 1506 put( "'\\b'" ); 1507 return; 1508 case '\f': 1509 put( "'\\f'" ); 1510 return; 1511 case '\n': 1512 put( "'\\n'" ); 1513 return; 1514 case '\r': 1515 put( "'\\r'" ); 1516 return; 1517 case '\t': 1518 put( "'\\t'" ); 1519 return; 1520 case '\v': 1521 put( "'\\v'" ); 1522 return; 1523 default: 1524 switch ( type ) 1525 { 1526 case 'a': 1527 if ( num >= 0x20 && num < 0x7F ) 1528 { 1529 put( '\'' ); 1530 put( cast(char)num ); 1531 put( '\'' ); 1532 return; 1533 } 1534 put( "\\x" ); 1535 putAsHex( num, 2 ); 1536 return; 1537 case 'u': 1538 put( "'\\u" ); 1539 putAsHex( num, 4 ); 1540 put( '\'' ); 1541 return; 1542 case 'w': 1543 put( "'\\U" ); 1544 putAsHex( num, 8 ); 1545 put( '\'' ); 1546 return; 1547 default: 1548 assert( 0 ); 1549 } 1550 } 1551 } 1552 case 'b': // bool 1553 put( decodeNumber() ? "true" : "false" ); 1554 return; 1555 case 'h', 't', 'k': // ubyte, ushort, uint 1556 put( sliceNumber() ); 1557 put( 'u' ); 1558 return; 1559 case 'l': // long 1560 put( sliceNumber() ); 1561 put( 'L' ); 1562 return; 1563 case 'm': // ulong 1564 put( sliceNumber() ); 1565 put( "uL" ); 1566 return; 1567 default: 1568 put( sliceNumber() ); 1569 return; 1570 } 1571 } 1572 1573 1574 /* 1575 TemplateArgs: 1576 TemplateArg 1577 TemplateArg TemplateArgs 1578 1579 TemplateArg: 1580 TemplateArgX 1581 H TemplateArgX 1582 1583 TemplateArgX: 1584 T Type 1585 V Type Value 1586 S Number_opt QualifiedName 1587 X ExternallyMangledName 1588 */ 1589 void parseTemplateArgs() scope 1590 { 1591 debug(trace) printf( "parseTemplateArgs+\n" ); 1592 debug(trace) scope(success) printf( "parseTemplateArgs-\n" ); 1593 1594 L_nextArg: 1595 for ( size_t n = 0; true; n++ ) 1596 { 1597 if ( front == 'H' ) 1598 popFront(); 1599 1600 switch ( front ) 1601 { 1602 case 'T': 1603 popFront(); 1604 putComma(n); 1605 parseType(); 1606 continue; 1607 case 'V': 1608 popFront(); 1609 putComma(n); 1610 // NOTE: In the few instances where the type is actually 1611 // desired in the output it should precede the value 1612 // generated by parseValue, so it is safe to simply 1613 // decrement len and let put/append do its thing. 1614 char t = front; // peek at type for parseValue 1615 if ( t == 'Q' ) 1616 t = peekBackref(); 1617 char[] name; 1618 // silent( delegate void() { name = parseType(); } ); 1619 // CHANGE: copy from original silent function - due to the delegate closure 1620 auto nn = len; name = parseType(); len = nn; 1621 parseValue( name, t ); 1622 continue; 1623 case 'S': 1624 popFront(); 1625 putComma(n); 1626 1627 if ( mayBeMangledNameArg() ) 1628 { 1629 auto l = len; 1630 auto p = pos; 1631 auto b = brp; 1632 try 1633 { 1634 debug(trace) printf( "may be mangled name arg\n" ); 1635 parseMangledNameArg(); 1636 continue; 1637 } 1638 catch ( ParseException e ) 1639 { 1640 len = l; 1641 pos = p; 1642 brp = b; 1643 debug(trace) printf( "not a mangled name arg\n" ); 1644 } 1645 } 1646 if ( isDigit( front ) && isDigit( peek( 1 ) ) ) 1647 { 1648 // ambiguity: length followed by qualified name (starting with number) 1649 // try all possible pairs of numbers 1650 auto qlen = decodeNumber() / 10; // last digit needed for QualifiedName 1651 pos--; 1652 auto l = len; 1653 auto p = pos; 1654 auto b = brp; 1655 while ( qlen > 0 ) 1656 { 1657 try 1658 { 1659 parseQualifiedName(); 1660 if ( pos == p + qlen ) 1661 continue L_nextArg; 1662 } 1663 catch ( ParseException e ) 1664 { 1665 } 1666 qlen /= 10; // retry with one digit less 1667 pos = --p; 1668 len = l; 1669 brp = b; 1670 } 1671 } 1672 parseQualifiedName(); 1673 continue; 1674 case 'X': 1675 popFront(); 1676 putComma(n); 1677 parseLName(); 1678 continue; 1679 default: 1680 return; 1681 } 1682 } 1683 } 1684 1685 1686 bool mayBeMangledNameArg() 1687 { 1688 debug(trace) printf( "mayBeMangledNameArg+\n" ); 1689 debug(trace) scope(success) printf( "mayBeMangledNameArg-\n" ); 1690 1691 auto p = pos; 1692 scope(exit) pos = p; 1693 if ( isDigit( buf[pos] ) ) 1694 { 1695 auto n = decodeNumber(); 1696 return n >= 4 && 1697 pos < buf.length && '_' == buf[pos++] && 1698 pos < buf.length && 'D' == buf[pos++] && 1699 isDigit( buf[pos] ); 1700 } 1701 else 1702 { 1703 return pos < buf.length && '_' == buf[pos++] && 1704 pos < buf.length && 'D' == buf[pos++] && 1705 isSymbolNameFront(); 1706 } 1707 } 1708 1709 1710 void parseMangledNameArg() 1711 { 1712 debug(trace) printf( "parseMangledNameArg+\n" ); 1713 debug(trace) scope(success) printf( "parseMangledNameArg-\n" ); 1714 1715 size_t n = 0; 1716 if ( isDigit( front ) ) 1717 n = decodeNumber(); 1718 parseMangledName( false, n ); 1719 } 1720 1721 1722 /* 1723 TemplateInstanceName: 1724 Number __T LName TemplateArgs Z 1725 */ 1726 void parseTemplateInstanceName(bool hasNumber) scope 1727 { 1728 debug(trace) printf( "parseTemplateInstanceName+\n" ); 1729 debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" ); 1730 1731 auto sav = pos; 1732 auto saveBrp = brp; 1733 scope(failure) 1734 { 1735 pos = sav; 1736 brp = saveBrp; 1737 } 1738 auto n = hasNumber ? decodeNumber() : 0; 1739 auto beg = pos; 1740 match( "__T" ); 1741 parseLName(); 1742 put( "!(" ); 1743 parseTemplateArgs(); 1744 match( 'Z' ); 1745 if ( hasNumber && pos - beg != n ) 1746 error( "Template name length mismatch" ); 1747 put( ')' ); 1748 } 1749 1750 1751 bool mayBeTemplateInstanceName() scope 1752 { 1753 debug(trace) printf( "mayBeTemplateInstanceName+\n" ); 1754 debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" ); 1755 1756 auto p = pos; 1757 scope(exit) pos = p; 1758 auto n = decodeNumber(); 1759 return n >= 5 && 1760 pos < buf.length && '_' == buf[pos++] && 1761 pos < buf.length && '_' == buf[pos++] && 1762 pos < buf.length && 'T' == buf[pos++]; 1763 } 1764 1765 1766 /* 1767 SymbolName: 1768 LName 1769 TemplateInstanceName 1770 */ 1771 void parseSymbolName() scope 1772 { 1773 debug(trace) printf( "parseSymbolName+\n" ); 1774 debug(trace) scope(success) printf( "parseSymbolName-\n" ); 1775 1776 // LName -> Number 1777 // TemplateInstanceName -> Number "__T" 1778 switch ( front ) 1779 { 1780 case '_': 1781 // no length encoding for templates for new mangling 1782 parseTemplateInstanceName(false); 1783 return; 1784 1785 case '0': .. case '9': 1786 if ( mayBeTemplateInstanceName() ) 1787 { 1788 auto t = len; 1789 1790 try 1791 { 1792 debug(trace) printf( "may be template instance name\n" ); 1793 parseTemplateInstanceName(true); 1794 return; 1795 } 1796 catch ( ParseException e ) 1797 { 1798 debug(trace) printf( "not a template instance name\n" ); 1799 len = t; 1800 } 1801 } 1802 goto case; 1803 case 'Q': 1804 parseLName(); 1805 return; 1806 default: 1807 error(); 1808 } 1809 } 1810 1811 // parse optional function arguments as part of a symbol name, i.e without return type 1812 // if keepAttr, the calling convention and function attributes are not discarded, but returned 1813 char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope 1814 { 1815 // try to demangle a function, in case we are pointing to some function local 1816 auto prevpos = pos; 1817 auto prevlen = len; 1818 auto prevbrp = brp; 1819 1820 char[] attr; 1821 try 1822 { 1823 if ( 'M' == front ) 1824 { 1825 // do not emit "needs this" 1826 popFront(); 1827 parseModifier(); 1828 } 1829 if ( isCallConvention( front ) ) 1830 { 1831 // we don't want calling convention and attributes in the qualified name 1832 parseCallConvention(); 1833 parseFuncAttr(); 1834 if ( keepAttr ) 1835 { 1836 attr = dst[prevlen .. len]; 1837 } 1838 else 1839 { 1840 len = prevlen; 1841 } 1842 1843 put( '(' ); 1844 parseFuncArguments(); 1845 put( ')' ); 1846 } 1847 } 1848 catch ( ParseException ) 1849 { 1850 // not part of a qualified name, so back up 1851 pos = prevpos; 1852 len = prevlen; 1853 brp = prevbrp; 1854 attr = null; 1855 } 1856 return attr; 1857 } 1858 1859 /* 1860 QualifiedName: 1861 SymbolName 1862 SymbolName QualifiedName 1863 */ 1864 char[] parseQualifiedName() return scope 1865 { 1866 debug(trace) printf( "parseQualifiedName+\n" ); 1867 debug(trace) scope(success) printf( "parseQualifiedName-\n" ); 1868 size_t beg = len; 1869 size_t n = 0; 1870 1871 do 1872 { 1873 if ( n++ ) 1874 put( '.' ); 1875 parseSymbolName(); 1876 parseFunctionTypeNoReturn(); 1877 1878 } while ( isSymbolNameFront() ); 1879 return dst[beg .. len]; 1880 } 1881 1882 1883 /* 1884 MangledName: 1885 _D QualifiedName Type 1886 _D QualifiedName M Type 1887 */ 1888 void parseMangledName( bool displayType, size_t n = 0 ) scope @nogc 1889 { 1890 debug(trace) printf( "parseMangledName+\n" ); 1891 debug(trace) scope(success) printf( "parseMangledName-\n" ); 1892 char[] name = null; 1893 1894 auto end = pos + n; 1895 1896 eat( '_' ); 1897 match( 'D' ); 1898 do 1899 { 1900 size_t beg = len; 1901 size_t nameEnd = len; 1902 char[] attr; 1903 do 1904 { 1905 if ( attr ) 1906 remove( attr ); // dump attributes of parent symbols 1907 if ( beg != len ) 1908 put( '.' ); 1909 parseSymbolName(); 1910 nameEnd = len; 1911 attr = parseFunctionTypeNoReturn( displayType ); 1912 1913 } while ( isSymbolNameFront() ); 1914 1915 if ( displayType ) 1916 { 1917 attr = shift( attr ); 1918 nameEnd = len - attr.length; // name includes function arguments 1919 } 1920 name = dst[beg .. nameEnd]; 1921 1922 debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr ); 1923 if ( 'M' == front ) 1924 popFront(); // has 'this' pointer 1925 1926 auto lastlen = len; 1927 auto type = parseType(); 1928 if ( displayType ) 1929 { 1930 if ( type.length ) 1931 put( ' ' ); 1932 // sort (name,attr,type) -> (attr,type,name) 1933 shift( name ); 1934 } 1935 else 1936 { 1937 // remove type 1938 assert( attr.length == 0 ); 1939 len = lastlen; 1940 } 1941 if ( pos >= buf.length || (n != 0 && pos >= end) ) 1942 return; 1943 1944 switch ( front ) 1945 { 1946 case 'T': // terminators when used as template alias parameter 1947 case 'V': 1948 case 'S': 1949 case 'Z': 1950 return; 1951 default: 1952 } 1953 put( '.' ); 1954 1955 } while ( true ); 1956 } 1957 1958 void parseMangledName() 1959 { 1960 parseMangledName( AddType.yes == addType ); 1961 } 1962 1963 char[] copyInput() return scope @nogc 1964 { 1965 if (dst.length < buf.length) 1966 // dst.length = buf.length; 1967 assert(0, "out of range"); // CHANGED: we pass slice of static array anyway 1968 char[] r = dst[0 .. buf.length]; 1969 r[] = buf[]; 1970 return r; 1971 } 1972 1973 char[] doDemangle(alias FUNC)() return scope @nogc 1974 { 1975 while ( true ) 1976 { 1977 try 1978 { 1979 debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr ); 1980 FUNC(); 1981 return dst[0 .. len]; 1982 } 1983 catch ( OverflowException e ) 1984 { 1985 // debug(trace) printf( "overflow... restarting\n" ); 1986 // auto a = minBufSize; 1987 // auto b = 2 * dst.length; 1988 // auto newsz = a < b ? b : a; 1989 // debug(info) printf( "growing dst to %lu bytes\n", newsz ); 1990 // dst.length = newsz; 1991 // pos = len = brp = 0; 1992 // continue; 1993 assert(0, "owerflow"); // CHANGE: we can't change length of static array provided as dst 1994 } 1995 catch ( ParseException e ) 1996 { 1997 debug(info) 1998 { 1999 auto msg = e.toString(); 2000 printf( "error: %.*s\n", cast(int) msg.length, msg.ptr ); 2001 } 2002 return copyInput(); 2003 } 2004 catch ( Exception e ) 2005 { 2006 assert( false ); // no other exceptions thrown 2007 } 2008 } 2009 } 2010 2011 char[] demangleName() nothrow @nogc 2012 { 2013 return doDemangle!parseMangledName(); 2014 } 2015 2016 char[] demangleType() nothrow 2017 { 2018 return doDemangle!parseType(); 2019 } 2020 } 2021 2022 /** 2023 * Demangles D mangled names. If it is not a D mangled name, it returns its 2024 * argument name. 2025 * 2026 * Params: 2027 * buf = The string to demangle. 2028 * dst = An optional destination buffer. 2029 * 2030 * Returns: 2031 * The demangled name or the original string if the name is not a mangled D 2032 * name. 2033 */ 2034 char[] demangle( const(char)[] buf, char[] dst = null ) nothrow pure @safe @nogc 2035 { 2036 auto d = Demangle!()(buf, dst); 2037 // fast path (avoiding throwing & catching exception) for obvious 2038 // non-D mangled names 2039 if (buf.length < 2 || !(buf[0] == 'D' || buf[0..2] == "_D")) 2040 return d.copyInput(); 2041 return d.demangleName(); 2042 } 2043 2044 // locally purified for internal use here only 2045 extern (C) private 2046 { 2047 pure @trusted @nogc nothrow pragma(mangle, "fakePureReprintReal") void pureReprintReal(char[] nptr); 2048 }