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