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