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 }