]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/d-demangle.c
MAINTAINERS (Write After Approval): Add myself.
[thirdparty/gcc.git] / libiberty / d-demangle.c
CommitLineData
43b1b9ed
IB
1/* Demangler for the D programming language
2 Copyright 2014 Free Software Foundation, Inc.
3 Written by Iain Buclaw (ibuclaw@gdcproject.org)
4
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11In addition to the permissions in the GNU Library General Public
12License, the Free Software Foundation gives you unlimited permission
13to link the compiled version of this file into combinations with other
14programs, and to distribute those combinations without any restriction
15coming from the use of this file. (The Library Public License
16restrictions do apply in other respects; for example, they cover
17modification of the file, and distribution when not linked into a
18combined executable.)
19
20Libiberty is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23Library General Public License for more details.
24
25You should have received a copy of the GNU Library General Public
26License along with libiberty; see the file COPYING.LIB.
27If not, see <http://www.gnu.org/licenses/>. */
28
29/* This file exports one function; dlang_demangle.
30
2a523cfe 31 This file imports strtol and strtod for decoding mangled literals. */
43b1b9ed
IB
32
33#ifdef HAVE_CONFIG_H
34#include "config.h"
35#endif
36
37#include "safe-ctype.h"
38
39#include <sys/types.h>
40#include <string.h>
41#include <stdio.h>
42
43#ifdef HAVE_STDLIB_H
44#include <stdlib.h>
45#else
46extern long strtol (const char *nptr, char **endptr, int base);
2a523cfe 47extern double strtod (const char *nptr, char **endptr);
43b1b9ed
IB
48#endif
49
50#include <demangle.h>
51#include "libiberty.h"
52
53/* A mini string-handling package */
54
55typedef struct string /* Beware: these aren't required to be */
56{ /* '\0' terminated. */
57 char *b; /* pointer to start of string */
58 char *p; /* pointer after last character */
59 char *e; /* pointer after end of allocated space */
60} string;
61
62static void
63string_need (string *s, int n)
64{
65 int tem;
66
67 if (s->b == NULL)
68 {
69 if (n < 32)
70 {
71 n = 32;
72 }
73 s->p = s->b = XNEWVEC (char, n);
74 s->e = s->b + n;
75 }
76 else if (s->e - s->p < n)
77 {
78 tem = s->p - s->b;
79 n += tem;
80 n *= 2;
81 s->b = XRESIZEVEC (char, s->b, n);
82 s->p = s->b + tem;
83 s->e = s->b + n;
84 }
85}
86
87static void
88string_delete (string *s)
89{
90 if (s->b != NULL)
91 {
92 XDELETEVEC (s->b);
93 s->b = s->e = s->p = NULL;
94 }
95}
96
97static void
98string_init (string *s)
99{
100 s->b = s->p = s->e = NULL;
101}
102
103static int
104string_length (string *s)
105{
106 if (s->p == s->b)
107 {
108 return 0;
109 }
110 return s->p - s->b;
111}
112
113static void
114string_setlength (string *s, int n)
115{
116 if (n - string_length (s) < 0)
117 {
118 s->p = s->b + n;
119 }
120}
121
122static void
123string_append (string *p, const char *s)
124{
125 int n = strlen (s);
126 string_need (p, n);
127 memcpy (p->p, s, n);
128 p->p += n;
129}
130
131static void
132string_appendn (string *p, const char *s, int n)
133{
134 if (n != 0)
135 {
136 string_need (p, n);
137 memcpy (p->p, s, n);
138 p->p += n;
139 }
140}
141
142static void
143string_prependn (string *p, const char *s, int n)
144{
145 char *q;
146
147 if (n != 0)
148 {
149 string_need (p, n);
150 for (q = p->p - 1; q >= p->b; q--)
151 {
152 q[n] = q[0];
153 }
154 memcpy (p->b, s, n);
155 p->p += n;
156 }
157}
158
159static void
160string_prepend (string *p, const char *s)
161{
162 if (s != NULL && *s != '\0')
163 {
164 string_prependn (p, s, strlen (s));
165 }
166}
167
168/* Prototypes for forward referenced functions */
169static const char *dlang_function_args (string *, const char *);
170
171static const char *dlang_type (string *, const char *);
172
173static const char *dlang_value (string *, const char *, const char *, char);
174
175static const char *dlang_parse_symbol (string *, const char *);
176
177static const char *dlang_parse_tuple (string *, const char *);
178
179static const char *dlang_parse_template (string *, const char *, long);
180
181
182/* Demangle the calling convention from MANGLED and append it to DECL.
183 Return the remaining string on success or NULL on failure. */
184static const char *
185dlang_call_convention (string *decl, const char *mangled)
186{
187 if (mangled == NULL || *mangled == '\0')
188 return mangled;
189
190 switch (*mangled)
191 {
192 case 'F': /* (D) */
193 mangled++;
194 break;
195 case 'U': /* (C) */
196 mangled++;
197 string_append (decl, "extern(C) ");
198 break;
199 case 'W': /* (Windows) */
200 mangled++;
201 string_append (decl, "extern(Windows) ");
202 break;
203 case 'V': /* (Pascal) */
204 mangled++;
205 string_append (decl, "extern(Pascal) ");
206 break;
207 case 'R': /* (C++) */
208 mangled++;
209 string_append (decl, "extern(C++) ");
210 break;
211 default:
212 return NULL;
213 }
214
215 return mangled;
216}
217
218/* Demangle the D function attributes from MANGLED and append it to DECL.
219 Return the remaining string on success or NULL on failure. */
220static const char *
221dlang_attributes (string *decl, const char *mangled)
222{
223 if (mangled == NULL || *mangled == '\0')
224 return mangled;
225
226 while (*mangled == 'N')
227 {
228 mangled++;
229 switch (*mangled)
230 {
231 case 'a': /* pure */
232 mangled++;
233 string_append (decl, "pure ");
234 continue;
235 case 'b': /* nothrow */
236 mangled++;
237 string_append (decl, "nothrow ");
238 continue;
239 case 'c': /* ref */
240 mangled++;
241 string_append (decl, "ref ");
242 continue;
243 case 'd': /* @property */
244 mangled++;
245 string_append (decl, "@property ");
246 continue;
247 case 'e': /* @trusted */
248 mangled++;
249 string_append (decl, "@trusted ");
250 continue;
251 case 'f': /* @safe */
252 mangled++;
253 string_append (decl, "@safe ");
254 continue;
255 case 'g':
256 case 'h':
257 /* inout parameter is represented as 'Ng'.
258 vector parameter is represented as 'Nh'.
259 If we see this, then we know we're really in the
260 parameter list. Rewind and break. */
261 mangled--;
262 break;
263 case 'i': /* @nogc */
264 mangled++;
265 string_append (decl, "@nogc ");
266 continue;
267 }
268 break;
269 }
270
271 return mangled;
272}
273
274/* Demangle the function type from MANGLED and append it to DECL.
275 Return the remaining string on success or NULL on failure. */
276static const char *
277dlang_function_type (string *decl, const char *mangled)
278{
279 string attr, args, type;
280 size_t szattr, szargs, sztype;
281
282 if (mangled == NULL || *mangled == '\0')
283 return mangled;
284
285 /* The order of the mangled string is:
286 CallConvention FuncAttrs Arguments ArgClose Type
287
288 The demangled string is re-ordered as:
289 CallConvention Type Arguments FuncAttrs
290 */
291 string_init (&attr);
292 string_init (&args);
293 string_init (&type);
294
295 /* Function call convention. */
296 mangled = dlang_call_convention (decl, mangled);
297
298 /* Function attributes. */
299 mangled = dlang_attributes (&attr, mangled);
300 szattr = string_length (&attr);
301
302 /* Function arguments. */
303 mangled = dlang_function_args (&args, mangled);
304 szargs = string_length (&args);
305
306 /* Function return type. */
307 mangled = dlang_type (&type, mangled);
308 sztype = string_length (&type);
309
310 /* Append to decl in order. */
311 string_appendn (decl, type.b, sztype);
312 string_append (decl, "(");
313 string_appendn (decl, args.b, szargs);
314 string_append (decl, ") ");
315 string_appendn (decl, attr.b, szattr);
316
317 string_delete (&attr);
318 string_delete (&args);
319 string_delete (&type);
320 return mangled;
321}
322
323/* Demangle the argument list from MANGLED and append it to DECL.
324 Return the remaining string on success or NULL on failure. */
325static const char *
326dlang_function_args (string *decl, const char *mangled)
327{
328 size_t n = 0;
329
330 while (mangled && *mangled != '\0')
331 {
332 switch (*mangled)
333 {
334 case 'X': /* (variadic T t...) style. */
335 mangled++;
336 string_append (decl, "...");
337 return mangled;
338 case 'Y': /* (variadic T t, ...) style. */
339 mangled++;
340 string_append (decl, ", ...");
341 return mangled;
342 case 'Z': /* Normal function. */
343 mangled++;
344 return mangled;
345 }
346
347 if (n++)
348 string_append (decl, ", ");
349
350 if (*mangled == 'M') /* scope(T) */
351 {
352 mangled++;
353 string_append (decl, "scope ");
354 }
355
356 switch (*mangled)
357 {
358 case 'J': /* out(T) */
359 mangled++;
360 string_append (decl, "out ");
361 break;
362 case 'K': /* ref(T) */
363 mangled++;
364 string_append (decl, "ref ");
365 break;
366 case 'L': /* lazy(T) */
367 mangled++;
368 string_append (decl, "lazy ");
369 break;
370 }
371 mangled = dlang_type (decl, mangled);
372 }
373
374 return mangled;
375}
376
377/* Demangle the type from MANGLED and append it to DECL.
378 Return the remaining string on success or NULL on failure. */
379static const char *
380dlang_type (string *decl, const char *mangled)
381{
382 if (mangled == NULL || *mangled == '\0')
383 return mangled;
384
385 switch (*mangled)
386 {
387 case 'O': /* shared(T) */
388 mangled++;
389 string_append (decl, "shared(");
390 mangled = dlang_type (decl, mangled);
391 string_append (decl, ")");
392 return mangled;
393 case 'x': /* const(T) */
394 mangled++;
395 string_append (decl, "const(");
396 mangled = dlang_type (decl, mangled);
397 string_append (decl, ")");
398 return mangled;
399 case 'y': /* immutable(T) */
400 mangled++;
401 string_append (decl, "immutable(");
402 mangled = dlang_type (decl, mangled);
403 string_append (decl, ")");
404 return mangled;
405 case 'N':
406 mangled++;
407 if (*mangled == 'g') /* wild(T) */
408 {
409 mangled++;
410 string_append (decl, "inout(");
411 mangled = dlang_type (decl, mangled);
412 string_append (decl, ")");
413 return mangled;
414 }
415 else if (*mangled == 'h') /* vector(T) */
416 {
417 mangled++;
418 string_append (decl, "__vector(");
419 mangled = dlang_type (decl, mangled);
420 string_append (decl, ")");
421 return mangled;
422 }
423 else
424 return NULL;
425 case 'A': /* dynamic array (T[]) */
426 mangled++;
427 mangled = dlang_type (decl, mangled);
428 string_append (decl, "[]");
429 return mangled;
430 case 'G': /* static array (T[N]) */
431 {
432 const char *numptr;
433 size_t num = 0;
434 mangled++;
435
436 numptr = mangled;
437 while (ISDIGIT (*mangled))
438 {
439 num++;
440 mangled++;
441 }
442 mangled = dlang_type (decl, mangled);
443 string_append (decl, "[");
444 string_appendn (decl, numptr, num);
445 string_append (decl, "]");
446 return mangled;
447 }
448 case 'H': /* associative array (T[T]) */
449 {
450 string type;
451 size_t sztype;
452 mangled++;
453
454 string_init (&type);
455 mangled = dlang_type (&type, mangled);
456 sztype = string_length (&type);
457
458 mangled = dlang_type (decl, mangled);
459 string_append (decl, "[");
460 string_appendn (decl, type.b, sztype);
461 string_append (decl, "]");
462
463 string_delete (&type);
464 return mangled;
465 }
466 case 'P': /* pointer (T*) */
467 mangled++;
468 mangled = dlang_type (decl, mangled);
469 string_append (decl, "*");
470 return mangled;
471 case 'I': /* ident T */
472 case 'C': /* class T */
473 case 'S': /* struct T */
474 case 'E': /* enum T */
475 case 'T': /* typedef T */
476 mangled++;
477 return dlang_parse_symbol (decl, mangled);
478 case 'D': /* delegate T */
479 mangled++;
480 mangled = dlang_function_type (decl, mangled);
481 string_append (decl, "delegate");
482 return mangled;
483 case 'B': /* tuple T */
484 mangled++;
485 return dlang_parse_tuple (decl, mangled);
486
487 /* Function types */
488 case 'F': case 'U': case 'W':
489 case 'V': case 'R':
490 mangled = dlang_function_type (decl, mangled);
491 string_append (decl, "function");
492 return mangled;
493
494 /* Basic types */
495 case 'n':
496 mangled++;
497 string_append (decl, "none");
498 return mangled;
499 case 'v':
500 mangled++;
501 string_append (decl, "void");
502 return mangled;
503 case 'g':
504 mangled++;
505 string_append (decl, "byte");
506 return mangled;
507 case 'h':
508 mangled++;
509 string_append (decl, "ubyte");
510 return mangled;
511 case 's':
512 mangled++;
513 string_append (decl, "short");
514 return mangled;
515 case 't':
516 mangled++;
517 string_append (decl, "ushort");
518 return mangled;
519 case 'i':
520 mangled++;
521 string_append (decl, "int");
522 return mangled;
523 case 'k':
524 mangled++;
525 string_append (decl, "uint");
526 return mangled;
527 case 'l':
528 mangled++;
529 string_append (decl, "long");
530 return mangled;
531 case 'm':
532 mangled++;
533 string_append (decl, "ulong");
534 return mangled;
535 case 'f':
536 mangled++;
537 string_append (decl, "float");
538 return mangled;
539 case 'd':
540 mangled++;
541 string_append (decl, "double");
542 return mangled;
543 case 'e':
544 mangled++;
545 string_append (decl, "real");
546 return mangled;
547
548 /* Imaginary and Complex types */
549 case 'o':
550 mangled++;
551 string_append (decl, "ifloat");
552 return mangled;
553 case 'p':
554 mangled++;
555 string_append (decl, "idouble");
556 return mangled;
557 case 'j':
558 mangled++;
559 string_append (decl, "ireal");
560 return mangled;
561 case 'q':
562 mangled++;
563 string_append (decl, "cfloat");
564 return mangled;
565 case 'r':
566 mangled++;
567 string_append (decl, "cdouble");
568 return mangled;
569 case 'c':
570 mangled++;
571 string_append (decl, "creal");
572 return mangled;
573
574 /* Other types */
575 case 'b':
576 mangled++;
577 string_append (decl, "bool");
578 return mangled;
579 case 'a':
580 mangled++;
581 string_append (decl, "char");
582 return mangled;
583 case 'u':
584 mangled++;
585 string_append (decl, "wchar");
586 return mangled;
587 case 'w':
588 mangled++;
589 string_append (decl, "dchar");
590 return mangled;
591
592 default: /* unhandled */
593 return NULL;
594 }
595}
596
597/* Extract the identifier from MANGLED and append it to DECL.
598 Return the remaining string on success or NULL on failure. */
599static const char *
600dlang_identifier (string *decl, const char *mangled)
601{
602 if (mangled == NULL || *mangled == '\0')
603 return mangled;
604
605 if (ISDIGIT (*mangled))
606 {
607 char *endptr;
608 long i = strtol (mangled, &endptr, 10);
609
610 if (endptr == NULL || i <= 0 || strlen (endptr) < (size_t) i)
611 return NULL;
612
613 mangled = endptr;
614
615 /* May be a template instance. */
616 if (i >= 5 && strncmp (mangled, "__T", 3) == 0)
617 {
618 /* Template symbol. */
619 if (ISDIGIT (mangled[3]) && mangled[3] != '0')
620 return dlang_parse_template (decl, mangled, i);
621
622 return NULL;
623 }
624
625 if (strncmp (mangled, "__ctor", i) == 0)
626 {
627 /* Constructor symbol for a class/struct. */
628 string_append (decl, "this");
629 mangled += i;
630 return mangled;
631 }
632 else if (strncmp (mangled, "__dtor", i) == 0)
633 {
634 /* Destructor symbol for a class/struct. */
635 string_append (decl, "~this");
636 mangled += i;
637 return mangled;
638 }
639 else if (strncmp (mangled, "__postblit", i) == 0)
640 {
641 /* Postblit symbol for a struct. */
642 string_append (decl, "this(this)");
643 mangled += i;
644 return mangled;
645 }
646 else if (strncmp (mangled, "__initZ", i+1) == 0)
647 {
648 /* The static initialiser for a given symbol. */
649 string_append (decl, "init$");
650 mangled += i + 1;
651 return mangled;
652 }
653 else if (strncmp (mangled, "__ClassZ", i+1) == 0)
654 {
655 /* The classinfo symbol for a given class. */
656 string_prepend (decl, "ClassInfo for ");
657 string_setlength (decl, string_length (decl) - 1);
658 mangled += i + 1;
659 return mangled;
660 }
661 else if (strncmp (mangled, "__vtblZ", i+1) == 0)
662 {
663 /* The vtable symbol for a given class. */
664 string_prepend (decl, "vtable for ");
665 string_setlength (decl, string_length (decl) - 1);
666 mangled += i + 1;
667 return mangled;
668 }
669 else if (strncmp (mangled, "__InterfaceZ", i+1) == 0)
670 {
671 /* The interface symbol for a given class. */
672 string_prepend (decl, "Interface for ");
673 string_setlength (decl, string_length (decl) - 1);
674 mangled += i + 1;
675 return mangled;
676 }
677 else if (strncmp (mangled, "__ModuleInfoZ", i+1) == 0)
678 {
679 /* The ModuleInfo symbol for a given module. */
680 string_prepend (decl, "ModuleInfo for ");
681 string_setlength (decl, string_length (decl) - 1);
682 mangled += i + 1;
683 return mangled;
684 }
685
686 string_appendn (decl, mangled, i);
687 mangled += i;
688 }
689 else
690 return NULL;
691
692 return mangled;
693}
694
695/* Extract the integer value from MANGLED and append it to DECL,
696 where TYPE is the type it should be represented as.
697 Return the remaining string on success or NULL on failure. */
698static const char *
699dlang_parse_integer (string *decl, const char *mangled, char type)
700{
701 if (type == 'a' || type == 'u' || type == 'w')
702 {
703 /* Parse character value. */
704 char value[10];
705 int pos = 10;
706 int width = 0;
707 char *endptr;
708 long val = strtol (mangled, &endptr, 10);
709
710 if (endptr == NULL || val < 0)
711 return NULL;
712
713 string_append (decl, "'");
714
715 if (type == 'a' && val >= 0x20 && val < 0x7F)
716 {
717 /* Represent as a character literal. */
718 char c = (char) val;
719 string_appendn (decl, &c, 1);
720 }
721 else
722 {
723 /* Represent as a hexadecimal value. */
724 switch (type)
725 {
726 case 'a': /* char */
727 string_append (decl, "\\x");
728 width = 2;
729 break;
730 case 'u': /* wchar */
731 string_append (decl, "\\u");
732 width = 4;
733 break;
734 case 'w': /* dchar */
735 string_append (decl, "\\U");
736 width = 8;
737 break;
738 }
739
740 while (val > 0)
741 {
742 int digit = val % 16;
743
744 if (digit < 10)
745 value[--pos] = (char)(digit + '0');
746 else
747 value[--pos] = (char)((digit - 10) + 'a');
748
749 val /= 16;
750 width--;
751 }
752
753 for (; width > 0; width--)
754 value[--pos] = '0';
755
756 string_appendn (decl, &(value[pos]), 10 - pos);
757 }
758 string_append (decl, "'");
759 mangled = endptr;
760 }
761 else if (type == 'b')
762 {
763 /* Parse boolean value. */
764 char *endptr;
765 long val = strtol (mangled, &endptr, 10);
766
767 if (endptr == NULL || val < 0)
768 return NULL;
769
770 string_append (decl, val ? "true" : "false");
771 mangled = endptr;
772 }
773 else
774 {
775 /* Parse integer value. */
776 const char *numptr = mangled;
777 size_t num = 0;
778
779 while (ISDIGIT (*mangled))
780 {
781 num++;
782 mangled++;
783 }
784 string_appendn (decl, numptr, num);
785
786 /* Append suffix. */
787 switch (type)
788 {
789 case 'h': /* ubyte */
790 case 't': /* ushort */
791 case 'k': /* uint */
792 string_append (decl, "u");
793 break;
794 case 'l': /* long */
795 string_append (decl, "L");
796 break;
797 case 'm': /* ulong */
798 string_append (decl, "uL");
799 break;
800 }
801 }
802
803 return mangled;
804}
805
806/* Extract the floating-point value from MANGLED and append it to DECL.
807 Return the remaining string on success or NULL on failure. */
808static const char *
809dlang_parse_real (string *decl, const char *mangled)
810{
811 char buffer[64];
812 int len = 0;
2a523cfe 813 double value;
43b1b9ed
IB
814 char *endptr;
815
816 /* Handle NAN and +-INF. */
817 if (strncmp (mangled, "NAN", 3) == 0)
818 {
819 string_append (decl, "NaN");
820 mangled += 3;
821 return mangled;
822 }
823 else if (strncmp (mangled, "INF", 3) == 0)
824 {
825 string_append (decl, "Inf");
826 mangled += 3;
827 return mangled;
828 }
829 else if (strncmp (mangled, "NINF", 4) == 0)
830 {
831 string_append (decl, "-Inf");
832 mangled += 4;
833 return mangled;
834 }
835
836 /* Hexadecimal prefix and leading bit. */
837 if (*mangled == 'N')
838 {
839 buffer[len++] = '-';
840 mangled++;
841 }
842
843 if (!ISXDIGIT (*mangled))
844 return NULL;
845
846 buffer[len++] = '0';
847 buffer[len++] = 'x';
848 buffer[len++] = *mangled;
849 buffer[len++] = '.';
850 mangled++;
851
852 /* Significand. */
853 while (ISXDIGIT (*mangled))
854 {
855 buffer[len++] = *mangled;
856 mangled++;
857 }
858
859 /* Exponent. */
860 if (*mangled != 'P')
861 return NULL;
862
863 buffer[len++] = 'p';
864 mangled++;
865
866 if (*mangled == 'N')
867 {
868 buffer[len++] = '-';
869 mangled++;
870 }
871
872 while (ISDIGIT (*mangled))
873 {
874 buffer[len++] = *mangled;
875 mangled++;
876 }
877
878 /* Convert buffer from hexadecimal to floating-point. */
879 buffer[len] = '\0';
2a523cfe 880 value = strtod (buffer, &endptr);
43b1b9ed
IB
881
882 if (endptr == NULL || endptr != (buffer + len))
883 return NULL;
884
2a523cfe 885 len = snprintf (buffer, sizeof(buffer), "%#g", value);
43b1b9ed
IB
886 string_appendn (decl, buffer, len);
887 return mangled;
888}
889
890/* Convert VAL from an ascii hexdigit to value. */
891static char
892ascii2hex (char val)
893{
894 if (val >= 'a' && val <= 'f')
895 return (val - 'a' + 10);
896
897 if (val >= 'A' && val <= 'F')
898 return (val - 'A' + 10);
899
900 if (val >= '0' && val <= '9')
901 return (val - '0');
902
903 return 0;
904}
905
906/* Extract the string value from MANGLED and append it to DECL.
907 Return the remaining string on success or NULL on failure. */
908static const char *
909dlang_parse_string (string *decl, const char *mangled)
910{
911 char type = *mangled;
912 char *endptr;
913 long len;
914
915 mangled++;
916 len = strtol (mangled, &endptr, 10);
917
918 if (endptr == NULL || len < 0)
919 return NULL;
920
921 mangled = endptr;
922 if (*mangled != '_')
923 return NULL;
924
925 mangled++;
926 string_append (decl, "\"");
927 while (len--)
928 {
929 if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
930 {
931 char a = ascii2hex (mangled[0]);
932 char b = ascii2hex (mangled[1]);
933 char val = (a << 4) | b;
934 string_appendn (decl, &val, 1);
935 }
936 else
937 return NULL;
938
939 mangled += 2;
940 }
941 string_append (decl, "\"");
942
943 if (type != 'a')
944 string_appendn (decl, &type, 1);
945
946 return mangled;
947}
948
949/* Extract the static array value from MANGLED and append it to DECL.
950 Return the remaining string on success or NULL on failure. */
951static const char *
952dlang_parse_arrayliteral (string *decl, const char *mangled)
953{
954 char *endptr;
955 long elements = strtol (mangled, &endptr, 10);
956
957 if (endptr == NULL || elements < 0)
958 return NULL;
959
960 mangled = endptr;
961 string_append (decl, "[");
962 while (elements--)
963 {
964 mangled = dlang_value (decl, mangled, NULL, '\0');
965 if (elements != 0)
966 string_append (decl, ", ");
967 }
968
969 string_append (decl, "]");
970 return mangled;
971}
972
973/* Extract the associative array value from MANGLED and append it to DECL.
974 Return the remaining string on success or NULL on failure. */
975static const char *
976dlang_parse_assocarray (string *decl, const char *mangled)
977{
978 char *endptr;
979 long elements = strtol (mangled, &endptr, 10);
980
981 if (endptr == NULL || elements < 0)
982 return NULL;
983
984 mangled = endptr;
985 string_append (decl, "[");
986 while (elements--)
987 {
988 mangled = dlang_value (decl, mangled, NULL, '\0');
989 string_append (decl, ":");
990 mangled = dlang_value (decl, mangled, NULL, '\0');
991
992 if (elements != 0)
993 string_append (decl, ", ");
994 }
995
996 string_append (decl, "]");
997 return mangled;
998}
999
1000/* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1001 Return the remaining string on success or NULL on failure. */
1002static const char *
1003dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1004{
1005 char *endptr;
1006 long args = strtol (mangled, &endptr, 10);
1007
1008 if (endptr == NULL || args < 0)
1009 return NULL;
1010
1011 mangled = endptr;
1012 if (name != NULL)
1013 string_append (decl, name);
1014
1015 string_append (decl, "(");
1016 while (args--)
1017 {
1018 mangled = dlang_value (decl, mangled, NULL, '\0');
1019 if (args != 0)
1020 string_append (decl, ", ");
1021 }
1022
1023 string_append (decl, ")");
1024 return mangled;
1025}
1026
1027/* Extract the value from MANGLED and append it to DECL.
1028 Return the remaining string on success or NULL on failure. */
1029static const char *
1030dlang_value (string *decl, const char *mangled, const char *name, char type)
1031{
1032 if (mangled == NULL || *mangled == '\0')
1033 return mangled;
1034
1035 switch (*mangled)
1036 {
1037 /* Null value. */
1038 case 'n':
1039 mangled++;
1040 string_append (decl, "null");
1041 break;
1042
1043 /* Integral values. */
1044 case 'N':
1045 mangled++;
1046 string_append (decl, "-");
1047 mangled = dlang_parse_integer (decl, mangled, type);
1048 break;
1049
1050 case 'i':
1051 mangled++;
1052 if (*mangled < '0' || *mangled > '9')
1053 return NULL;
1054 /* Fall through */
1055 case '0': case '1': case '2': case '3': case '4':
1056 case '5': case '6': case '7': case '8': case '9':
1057 mangled = dlang_parse_integer (decl, mangled, type);
1058 break;
1059
1060 /* Real value. */
1061 case 'e':
1062 mangled++;
1063 mangled = dlang_parse_real (decl, mangled);
1064 break;
1065
1066 /* Complex value. */
1067 case 'c':
1068 mangled++;
1069 mangled = dlang_parse_real (decl, mangled);
1070 string_append (decl, "+");
1071 if (mangled == NULL || *mangled != 'c')
1072 return NULL;
1073 mangled++;
1074 mangled = dlang_parse_real (decl, mangled);
1075 string_append (decl, "i");
1076 break;
1077
1078 /* String values. */
1079 case 'a': /* UTF8 */
1080 case 'w': /* UTF16 */
1081 case 'd': /* UTF32 */
1082 mangled = dlang_parse_string (decl, mangled);
1083 break;
1084
1085 /* Array values. */
1086 case 'A':
1087 mangled++;
1088 if (type == 'H')
1089 mangled = dlang_parse_assocarray (decl, mangled);
1090 else
1091 mangled = dlang_parse_arrayliteral (decl, mangled);
1092 break;
1093
1094 /* Struct values. */
1095 case 'S':
1096 mangled++;
1097 mangled = dlang_parse_structlit (decl, mangled, name);
1098 break;
1099
1100 default:
1101 return NULL;
1102 }
1103
1104 return mangled;
1105}
1106
1107static int
1108dlang_call_convention_p (const char *mangled)
1109{
1110 size_t i;
1111
1112 switch (*mangled)
1113 {
1114 case 'F': case 'U': case 'V':
1115 case 'W': case 'R':
1116 return 1;
1117
1118 case 'M': /* Prefix for functions needing 'this' */
1119 i = 1;
1120 if (mangled[i] == 'x')
1121 i++;
1122
1123 switch (mangled[i])
1124 {
1125 case 'F': case 'U': case 'V':
1126 case 'W': case 'R':
1127 return 1;
1128 }
1129
1130 default:
1131 return 0;
1132 }
1133}
1134
1135/* Extract and demangle the symbol in MANGLED and append it to DECL.
1136 Returns the remaining signature on success or NULL on failure. */
1137static const char *
1138dlang_parse_symbol (string *decl, const char *mangled)
1139{
1140 size_t n = 0;
1141 do
1142 {
1143 if (n++)
1144 string_append (decl, ".");
1145
1146 mangled = dlang_identifier (decl, mangled);
1147
1148 if (mangled && dlang_call_convention_p (mangled))
1149 {
1150 int saved;
1151
1152 /* Skip over 'this' parameter. */
1153 if (*mangled == 'M')
1154 mangled += (mangled[1] == 'x') ? 2 : 1;
1155
1156 /* Skip over calling convention and attributes in qualified name. */
1157 saved = string_length (decl);
1158 mangled = dlang_call_convention (decl, mangled);
1159 mangled = dlang_attributes (decl, mangled);
1160 string_setlength (decl, saved);
1161
1162 string_append (decl, "(");
1163 mangled = dlang_function_args (decl, mangled);
1164 string_append (decl, ")");
1165
1166 /* Demangle the function return type as a kind of sanity test. */
1167 if (mangled && !ISDIGIT (*mangled))
1168 {
1169 saved = string_length (decl);
1170 mangled = dlang_type (decl, mangled);
1171 string_setlength (decl, saved);
1172 }
1173 }
1174 }
1175 while (mangled && ISDIGIT (*mangled));
1176
1177 return mangled;
1178}
1179
1180/* Demangle the tuple from MANGLED and append it to DECL.
1181 Return the remaining string on success or NULL on failure. */
1182static const char *
1183dlang_parse_tuple (string *decl, const char *mangled)
1184{
1185 char *endptr;
1186 long elements = strtol (mangled, &endptr, 10);
1187
1188 if (endptr == NULL || elements < 0)
1189 return NULL;
1190
1191 mangled = endptr;
1192 string_append (decl, "Tuple!(");
1193
1194 while (elements--)
1195 {
1196 mangled = dlang_type (decl, mangled);
1197 if (elements != 0)
1198 string_append (decl, ", ");
1199 }
1200
1201 string_append (decl, ")");
1202 return mangled;
1203}
1204
1205/* Demangle the argument list from MANGLED and append it to DECL.
1206 Return the remaining string on success or NULL on failure. */
1207static const char *
1208dlang_template_args (string *decl, const char *mangled)
1209{
1210 size_t n = 0;
1211
1212 while (mangled && *mangled != '\0')
1213 {
1214 switch (*mangled)
1215 {
1216 case 'Z': /* End of parameter list. */
1217 mangled++;
1218 return mangled;
1219 }
1220
1221 if (n++)
1222 string_append (decl, ", ");
1223
1224 switch (*mangled)
1225 {
1226 case 'S': /* Symbol parameter. */
1227 mangled++;
1228 mangled = dlang_parse_symbol (decl, mangled);
1229 break;
1230 case 'T': /* Type parameter. */
1231 mangled++;
1232 mangled = dlang_type (decl, mangled);
1233 break;
1234 case 'V': /* Value parameter. */
1235 {
1236 string name;
1237 char type;
1238
1239 /* Peek at the type. */
1240 mangled++;
1241 type = *mangled;
1242
1243 /* In the few instances where the type is actually desired in
1244 the output, it should precede the value from dlang_value. */
1245 string_init (&name);
1246 mangled = dlang_type (&name, mangled);
1247 string_need (&name, 1);
1248 *(name.p) = '\0';
1249
1250 mangled = dlang_value (decl, mangled, name.b, type);
1251 string_delete (&name);
1252 break;
1253 }
1254
1255 default:
1256 return NULL;
1257 }
1258 }
1259
1260 return mangled;
1261}
1262
1263/* Extract and demangle the template symbol in MANGLED, expected to
1264 be made up of LEN characters, and append it to DECL.
1265 Returns the remaining signature on success or NULL on failure. */
1266static const char *
1267dlang_parse_template (string *decl, const char *mangled, long len)
1268{
1269 const char *start = mangled;
1270
1271 /* Template instance names have the types and values of its parameters
1272 encoded into it.
1273
1274 TemplateInstanceName:
1275 Number __T LName TemplateArgs Z
1276 ^
1277 The start pointer should be at the above location, and LEN should be
1278 the value of the decoded number.
1279 */
1280 if (strncmp (mangled, "__T", 3) != 0)
1281 return NULL;
1282
1283 mangled += 3;
1284
1285 /* Template identifier. */
1286 mangled = dlang_identifier (decl, mangled);
1287
1288 /* Template arguments. */
1289 string_append (decl, "!(");
1290 mangled = dlang_template_args (decl, mangled);
1291 string_append (decl, ")");
1292
1293 /* Check for template name length mismatch. */
1294 if (mangled && (mangled - start) != len)
1295 return NULL;
1296
1297 return mangled;
1298}
1299
1300/* Extract and demangle the symbol in MANGLED. Returns the demangled
1301 signature on success or NULL on failure. */
1302
1303char *
1304dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1305{
1306 string decl;
1307 char *demangled = NULL;
1308
1309 if (mangled == NULL || *mangled == '\0')
1310 return NULL;
1311
1312 if (strncmp (mangled, "_D", 2) != 0)
1313 return NULL;
1314
1315 string_init (&decl);
1316
1317 if (strcmp (mangled, "_Dmain") == 0)
1318 {
1319 string_append (&decl, "D main");
1320 }
1321 else
1322 {
1323 mangled += 2;
1324
1325 if (dlang_parse_symbol (&decl, mangled) == NULL)
1326 string_delete (&decl);
1327 }
1328
1329 if (string_length (&decl) > 0)
1330 {
1331 string_need (&decl, 1);
1332 *(decl.p) = '\0';
1333 demangled = decl.b;
1334 }
1335
1336 return demangled;
1337}
1338