]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/d-demangle.c
d-demangle.c (dlang_type): Handle function types only in the context of seeing a...
[thirdparty/gcc.git] / libiberty / d-demangle.c
CommitLineData
43b1b9ed 1/* Demangler for the D programming language
0f4b8b31 2 Copyright 2014, 2015, 2016 Free Software Foundation, Inc.
43b1b9ed
IB
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
fd91ffb8 31 This file imports strtol 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);
43b1b9ed
IB
47#endif
48
49#include <demangle.h>
50#include "libiberty.h"
51
52/* A mini string-handling package */
53
54typedef struct string /* Beware: these aren't required to be */
55{ /* '\0' terminated. */
56 char *b; /* pointer to start of string */
57 char *p; /* pointer after last character */
58 char *e; /* pointer after end of allocated space */
59} string;
60
61static void
62string_need (string *s, int n)
63{
64 int tem;
65
66 if (s->b == NULL)
67 {
68 if (n < 32)
69 {
70 n = 32;
71 }
72 s->p = s->b = XNEWVEC (char, n);
73 s->e = s->b + n;
74 }
75 else if (s->e - s->p < n)
76 {
77 tem = s->p - s->b;
78 n += tem;
79 n *= 2;
80 s->b = XRESIZEVEC (char, s->b, n);
81 s->p = s->b + tem;
82 s->e = s->b + n;
83 }
84}
85
86static void
87string_delete (string *s)
88{
89 if (s->b != NULL)
90 {
91 XDELETEVEC (s->b);
92 s->b = s->e = s->p = NULL;
93 }
94}
95
96static void
97string_init (string *s)
98{
99 s->b = s->p = s->e = NULL;
100}
101
102static int
103string_length (string *s)
104{
105 if (s->p == s->b)
106 {
107 return 0;
108 }
109 return s->p - s->b;
110}
111
112static void
113string_setlength (string *s, int n)
114{
115 if (n - string_length (s) < 0)
116 {
117 s->p = s->b + n;
118 }
119}
120
121static void
122string_append (string *p, const char *s)
123{
124 int n = strlen (s);
125 string_need (p, n);
126 memcpy (p->p, s, n);
127 p->p += n;
128}
129
130static void
131string_appendn (string *p, const char *s, int n)
132{
133 if (n != 0)
134 {
135 string_need (p, n);
136 memcpy (p->p, s, n);
137 p->p += n;
138 }
139}
140
141static void
142string_prependn (string *p, const char *s, int n)
143{
144 char *q;
145
146 if (n != 0)
147 {
148 string_need (p, n);
149 for (q = p->p - 1; q >= p->b; q--)
150 {
151 q[n] = q[0];
152 }
153 memcpy (p->b, s, n);
154 p->p += n;
155 }
156}
157
158static void
159string_prepend (string *p, const char *s)
160{
161 if (s != NULL && *s != '\0')
162 {
163 string_prependn (p, s, strlen (s));
164 }
165}
166
7e865541
IB
167/* What kinds of symbol we could be parsing. */
168enum dlang_symbol_kinds
169{
170 /* Top-level symbol, needs it's type checked. */
171 dlang_top_level,
172 /* Function symbol, needs it's type checked. */
173 dlang_function,
174 /* Strongly typed name, such as for classes, structs and enums. */
175 dlang_type_name,
176 /* Template identifier. */
177 dlang_template_ident,
178 /* Template symbol parameter. */
179 dlang_template_param
180};
181
43b1b9ed
IB
182/* Prototypes for forward referenced functions */
183static const char *dlang_function_args (string *, const char *);
184
185static const char *dlang_type (string *, const char *);
186
187static const char *dlang_value (string *, const char *, const char *, char);
188
7e865541
IB
189static const char *dlang_parse_symbol (string *, const char *,
190 enum dlang_symbol_kinds);
43b1b9ed
IB
191
192static const char *dlang_parse_tuple (string *, const char *);
193
194static const char *dlang_parse_template (string *, const char *, long);
195
196
197/* Demangle the calling convention from MANGLED and append it to DECL.
198 Return the remaining string on success or NULL on failure. */
199static const char *
200dlang_call_convention (string *decl, const char *mangled)
201{
202 if (mangled == NULL || *mangled == '\0')
76b41cad 203 return NULL;
43b1b9ed
IB
204
205 switch (*mangled)
206 {
207 case 'F': /* (D) */
208 mangled++;
209 break;
210 case 'U': /* (C) */
211 mangled++;
212 string_append (decl, "extern(C) ");
213 break;
214 case 'W': /* (Windows) */
215 mangled++;
216 string_append (decl, "extern(Windows) ");
217 break;
218 case 'V': /* (Pascal) */
219 mangled++;
220 string_append (decl, "extern(Pascal) ");
221 break;
222 case 'R': /* (C++) */
223 mangled++;
224 string_append (decl, "extern(C++) ");
225 break;
226 default:
227 return NULL;
228 }
229
230 return mangled;
231}
232
fa66ced4
IB
233/* Extract the type modifiers from MANGLED and append them to DECL.
234 Returns the remaining signature on success or NULL on failure. */
235static const char *
236dlang_type_modifiers (string *decl, const char *mangled)
237{
238 if (mangled == NULL || *mangled == '\0')
239 return NULL;
240
241 switch (*mangled)
242 {
243 case 'x': /* const */
244 mangled++;
245 string_append (decl, " const");
246 return mangled;
247 case 'y': /* immutable */
248 mangled++;
249 string_append (decl, " immutable");
250 return mangled;
251 case 'O': /* shared */
252 mangled++;
253 string_append (decl, " shared");
254 return dlang_type_modifiers (decl, mangled);
255 case 'N':
256 mangled++;
257 if (*mangled == 'g') /* wild */
258 {
259 mangled++;
260 string_append (decl, " inout");
261 return dlang_type_modifiers (decl, mangled);
262 }
263 else
264 return NULL;
265
266 default:
267 return mangled;
268 }
269}
270
43b1b9ed
IB
271/* Demangle the D function attributes from MANGLED and append it to DECL.
272 Return the remaining string on success or NULL on failure. */
273static const char *
274dlang_attributes (string *decl, const char *mangled)
275{
276 if (mangled == NULL || *mangled == '\0')
76b41cad 277 return NULL;
43b1b9ed
IB
278
279 while (*mangled == 'N')
280 {
281 mangled++;
282 switch (*mangled)
283 {
284 case 'a': /* pure */
285 mangled++;
286 string_append (decl, "pure ");
287 continue;
288 case 'b': /* nothrow */
289 mangled++;
290 string_append (decl, "nothrow ");
291 continue;
292 case 'c': /* ref */
293 mangled++;
294 string_append (decl, "ref ");
295 continue;
296 case 'd': /* @property */
297 mangled++;
298 string_append (decl, "@property ");
299 continue;
300 case 'e': /* @trusted */
301 mangled++;
302 string_append (decl, "@trusted ");
303 continue;
304 case 'f': /* @safe */
305 mangled++;
306 string_append (decl, "@safe ");
307 continue;
308 case 'g':
309 case 'h':
7ce4461f 310 case 'k':
43b1b9ed
IB
311 /* inout parameter is represented as 'Ng'.
312 vector parameter is represented as 'Nh'.
7ce4461f 313 return paramenter is represented as 'Nk'.
43b1b9ed
IB
314 If we see this, then we know we're really in the
315 parameter list. Rewind and break. */
316 mangled--;
317 break;
318 case 'i': /* @nogc */
319 mangled++;
320 string_append (decl, "@nogc ");
321 continue;
7ce4461f
IB
322 case 'j': /* return */
323 mangled++;
324 string_append (decl, "return ");
325 continue;
326
327 default: /* unknown attribute */
328 return NULL;
43b1b9ed
IB
329 }
330 break;
331 }
332
333 return mangled;
334}
335
336/* Demangle the function type from MANGLED and append it to DECL.
337 Return the remaining string on success or NULL on failure. */
338static const char *
339dlang_function_type (string *decl, const char *mangled)
340{
341 string attr, args, type;
342 size_t szattr, szargs, sztype;
343
344 if (mangled == NULL || *mangled == '\0')
76b41cad 345 return NULL;
43b1b9ed
IB
346
347 /* The order of the mangled string is:
348 CallConvention FuncAttrs Arguments ArgClose Type
349
350 The demangled string is re-ordered as:
351 CallConvention Type Arguments FuncAttrs
352 */
353 string_init (&attr);
354 string_init (&args);
355 string_init (&type);
356
357 /* Function call convention. */
358 mangled = dlang_call_convention (decl, mangled);
359
360 /* Function attributes. */
361 mangled = dlang_attributes (&attr, mangled);
362 szattr = string_length (&attr);
363
364 /* Function arguments. */
365 mangled = dlang_function_args (&args, mangled);
366 szargs = string_length (&args);
367
368 /* Function return type. */
369 mangled = dlang_type (&type, mangled);
370 sztype = string_length (&type);
371
372 /* Append to decl in order. */
373 string_appendn (decl, type.b, sztype);
374 string_append (decl, "(");
375 string_appendn (decl, args.b, szargs);
376 string_append (decl, ") ");
377 string_appendn (decl, attr.b, szattr);
378
379 string_delete (&attr);
380 string_delete (&args);
381 string_delete (&type);
382 return mangled;
383}
384
385/* Demangle the argument list from MANGLED and append it to DECL.
386 Return the remaining string on success or NULL on failure. */
387static const char *
388dlang_function_args (string *decl, const char *mangled)
389{
390 size_t n = 0;
391
392 while (mangled && *mangled != '\0')
393 {
394 switch (*mangled)
395 {
396 case 'X': /* (variadic T t...) style. */
397 mangled++;
398 string_append (decl, "...");
399 return mangled;
400 case 'Y': /* (variadic T t, ...) style. */
401 mangled++;
402 string_append (decl, ", ...");
403 return mangled;
404 case 'Z': /* Normal function. */
405 mangled++;
406 return mangled;
407 }
408
409 if (n++)
410 string_append (decl, ", ");
411
412 if (*mangled == 'M') /* scope(T) */
413 {
414 mangled++;
415 string_append (decl, "scope ");
416 }
417
7ce4461f
IB
418 if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */
419 {
420 mangled += 2;
421 string_append (decl, "return ");
422 }
423
43b1b9ed
IB
424 switch (*mangled)
425 {
426 case 'J': /* out(T) */
427 mangled++;
428 string_append (decl, "out ");
429 break;
430 case 'K': /* ref(T) */
431 mangled++;
432 string_append (decl, "ref ");
433 break;
434 case 'L': /* lazy(T) */
435 mangled++;
436 string_append (decl, "lazy ");
437 break;
438 }
439 mangled = dlang_type (decl, mangled);
440 }
441
442 return mangled;
443}
444
445/* Demangle the type from MANGLED and append it to DECL.
446 Return the remaining string on success or NULL on failure. */
447static const char *
448dlang_type (string *decl, const char *mangled)
449{
450 if (mangled == NULL || *mangled == '\0')
76b41cad 451 return NULL;
43b1b9ed
IB
452
453 switch (*mangled)
454 {
455 case 'O': /* shared(T) */
456 mangled++;
457 string_append (decl, "shared(");
458 mangled = dlang_type (decl, mangled);
459 string_append (decl, ")");
460 return mangled;
461 case 'x': /* const(T) */
462 mangled++;
463 string_append (decl, "const(");
464 mangled = dlang_type (decl, mangled);
465 string_append (decl, ")");
466 return mangled;
467 case 'y': /* immutable(T) */
468 mangled++;
469 string_append (decl, "immutable(");
470 mangled = dlang_type (decl, mangled);
471 string_append (decl, ")");
472 return mangled;
473 case 'N':
474 mangled++;
475 if (*mangled == 'g') /* wild(T) */
476 {
477 mangled++;
478 string_append (decl, "inout(");
479 mangled = dlang_type (decl, mangled);
480 string_append (decl, ")");
481 return mangled;
482 }
483 else if (*mangled == 'h') /* vector(T) */
484 {
485 mangled++;
486 string_append (decl, "__vector(");
487 mangled = dlang_type (decl, mangled);
488 string_append (decl, ")");
489 return mangled;
490 }
491 else
492 return NULL;
493 case 'A': /* dynamic array (T[]) */
494 mangled++;
495 mangled = dlang_type (decl, mangled);
496 string_append (decl, "[]");
497 return mangled;
498 case 'G': /* static array (T[N]) */
499 {
500 const char *numptr;
501 size_t num = 0;
502 mangled++;
503
504 numptr = mangled;
505 while (ISDIGIT (*mangled))
506 {
507 num++;
508 mangled++;
509 }
510 mangled = dlang_type (decl, mangled);
511 string_append (decl, "[");
512 string_appendn (decl, numptr, num);
513 string_append (decl, "]");
514 return mangled;
515 }
516 case 'H': /* associative array (T[T]) */
517 {
518 string type;
519 size_t sztype;
520 mangled++;
521
522 string_init (&type);
523 mangled = dlang_type (&type, mangled);
524 sztype = string_length (&type);
525
526 mangled = dlang_type (decl, mangled);
527 string_append (decl, "[");
528 string_appendn (decl, type.b, sztype);
529 string_append (decl, "]");
530
531 string_delete (&type);
532 return mangled;
533 }
534 case 'P': /* pointer (T*) */
535 mangled++;
0f4b8b31
IB
536 /* Function pointer types don't include the trailing asterisk. */
537 switch (*mangled)
538 {
539 case 'F': case 'U': case 'W':
540 case 'V': case 'R':
541 mangled = dlang_function_type (decl, mangled);
542 string_append (decl, "function");
543 return mangled;
544 }
43b1b9ed
IB
545 mangled = dlang_type (decl, mangled);
546 string_append (decl, "*");
547 return mangled;
548 case 'I': /* ident T */
549 case 'C': /* class T */
550 case 'S': /* struct T */
551 case 'E': /* enum T */
552 case 'T': /* typedef T */
553 mangled++;
7e865541 554 return dlang_parse_symbol (decl, mangled, dlang_type_name);
43b1b9ed 555 case 'D': /* delegate T */
fa66ced4
IB
556 {
557 string mods;
558 size_t szmods;
43b1b9ed 559 mangled++;
fa66ced4
IB
560
561 string_init (&mods);
562 mangled = dlang_type_modifiers (&mods, mangled);
563 szmods = string_length (&mods);
564
43b1b9ed
IB
565 mangled = dlang_function_type (decl, mangled);
566 string_append (decl, "delegate");
fa66ced4
IB
567 string_appendn (decl, mods.b, szmods);
568
569 string_delete (&mods);
43b1b9ed 570 return mangled;
fa66ced4 571 }
43b1b9ed
IB
572 case 'B': /* tuple T */
573 mangled++;
574 return dlang_parse_tuple (decl, mangled);
575
43b1b9ed
IB
576 /* Basic types */
577 case 'n':
578 mangled++;
579 string_append (decl, "none");
580 return mangled;
581 case 'v':
582 mangled++;
583 string_append (decl, "void");
584 return mangled;
585 case 'g':
586 mangled++;
587 string_append (decl, "byte");
588 return mangled;
589 case 'h':
590 mangled++;
591 string_append (decl, "ubyte");
592 return mangled;
593 case 's':
594 mangled++;
595 string_append (decl, "short");
596 return mangled;
597 case 't':
598 mangled++;
599 string_append (decl, "ushort");
600 return mangled;
601 case 'i':
602 mangled++;
603 string_append (decl, "int");
604 return mangled;
605 case 'k':
606 mangled++;
607 string_append (decl, "uint");
608 return mangled;
609 case 'l':
610 mangled++;
611 string_append (decl, "long");
612 return mangled;
613 case 'm':
614 mangled++;
615 string_append (decl, "ulong");
616 return mangled;
617 case 'f':
618 mangled++;
619 string_append (decl, "float");
620 return mangled;
621 case 'd':
622 mangled++;
623 string_append (decl, "double");
624 return mangled;
625 case 'e':
626 mangled++;
627 string_append (decl, "real");
628 return mangled;
629
630 /* Imaginary and Complex types */
631 case 'o':
632 mangled++;
633 string_append (decl, "ifloat");
634 return mangled;
635 case 'p':
636 mangled++;
637 string_append (decl, "idouble");
638 return mangled;
639 case 'j':
640 mangled++;
641 string_append (decl, "ireal");
642 return mangled;
643 case 'q':
644 mangled++;
645 string_append (decl, "cfloat");
646 return mangled;
647 case 'r':
648 mangled++;
649 string_append (decl, "cdouble");
650 return mangled;
651 case 'c':
652 mangled++;
653 string_append (decl, "creal");
654 return mangled;
655
656 /* Other types */
657 case 'b':
658 mangled++;
659 string_append (decl, "bool");
660 return mangled;
661 case 'a':
662 mangled++;
663 string_append (decl, "char");
664 return mangled;
665 case 'u':
666 mangled++;
667 string_append (decl, "wchar");
668 return mangled;
669 case 'w':
670 mangled++;
671 string_append (decl, "dchar");
672 return mangled;
59251a73
IB
673 case 'z':
674 mangled++;
675 switch (*mangled)
676 {
677 case 'i':
678 mangled++;
679 string_append (decl, "cent");
680 return mangled;
681 case 'k':
682 mangled++;
683 string_append (decl, "ucent");
684 return mangled;
685 }
686 return NULL;
43b1b9ed
IB
687
688 default: /* unhandled */
689 return NULL;
690 }
691}
692
693/* Extract the identifier from MANGLED and append it to DECL.
694 Return the remaining string on success or NULL on failure. */
695static const char *
7e865541
IB
696dlang_identifier (string *decl, const char *mangled,
697 enum dlang_symbol_kinds kind)
43b1b9ed 698{
7e865541
IB
699 char *endptr;
700 long len;
701
43b1b9ed 702 if (mangled == NULL || *mangled == '\0')
76b41cad 703 return NULL;
43b1b9ed 704
7e865541
IB
705 len = strtol (mangled, &endptr, 10);
706
707 if (endptr == NULL || len <= 0)
708 return NULL;
709
710 /* In template parameter symbols, the first character of the mangled
711 name can be a digit. This causes ambiguity issues because the
712 digits of the two numbers are adjacent. */
713 if (kind == dlang_template_param)
43b1b9ed 714 {
7e865541
IB
715 long psize = len;
716 char *pend;
717 int saved = string_length (decl);
718
719 /* Work backwards until a match is found. */
720 for (pend = endptr; endptr != NULL; pend--)
721 {
722 mangled = pend;
43b1b9ed 723
7e865541
IB
724 /* Reached the beginning of the pointer to the name length,
725 try parsing the entire symbol. */
726 if (psize == 0)
727 {
728 psize = len;
729 pend = endptr;
730 endptr = NULL;
731 }
732
733 /* Check whether template parameter is a function with a valid
734 return type or an untyped identifier. */
735 if (ISDIGIT (*mangled))
736 mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident);
737 else if (strncmp (mangled, "_D", 2) == 0)
738 {
739 mangled += 2;
740 mangled = dlang_parse_symbol (decl, mangled, dlang_function);
741 }
742
743 /* Check for name length mismatch. */
744 if (mangled && (mangled - pend) == psize)
745 return mangled;
746
747 psize /= 10;
748 string_setlength (decl, saved);
749 }
750
751 /* No match on any combinations. */
752 return NULL;
753 }
754 else
755 {
756 if (strlen (endptr) < (size_t) len)
43b1b9ed
IB
757 return NULL;
758
759 mangled = endptr;
760
761 /* May be a template instance. */
7e865541 762 if (len >= 5 && strncmp (mangled, "__T", 3) == 0)
43b1b9ed
IB
763 {
764 /* Template symbol. */
765 if (ISDIGIT (mangled[3]) && mangled[3] != '0')
7e865541 766 return dlang_parse_template (decl, mangled, len);
43b1b9ed
IB
767
768 return NULL;
769 }
770
7e865541 771 switch (len)
43b1b9ed 772 {
5cc158e9 773 case 6:
7e865541 774 if (strncmp (mangled, "__ctor", len) == 0)
5cc158e9
IB
775 {
776 /* Constructor symbol for a class/struct. */
777 string_append (decl, "this");
7e865541 778 mangled += len;
5cc158e9
IB
779 return mangled;
780 }
7e865541 781 else if (strncmp (mangled, "__dtor", len) == 0)
5cc158e9
IB
782 {
783 /* Destructor symbol for a class/struct. */
784 string_append (decl, "~this");
7e865541 785 mangled += len;
5cc158e9
IB
786 return mangled;
787 }
7e865541 788 else if (strncmp (mangled, "__initZ", len+1) == 0)
5cc158e9
IB
789 {
790 /* The static initialiser for a given symbol. */
791 string_append (decl, "init$");
7e865541 792 mangled += len;
5cc158e9
IB
793 return mangled;
794 }
7e865541 795 else if (strncmp (mangled, "__vtblZ", len+1) == 0)
5cc158e9
IB
796 {
797 /* The vtable symbol for a given class. */
798 string_prepend (decl, "vtable for ");
799 string_setlength (decl, string_length (decl) - 1);
7e865541 800 mangled += len;
5cc158e9
IB
801 return mangled;
802 }
803 break;
804
805 case 7:
7e865541 806 if (strncmp (mangled, "__ClassZ", len+1) == 0)
5cc158e9
IB
807 {
808 /* The classinfo symbol for a given class. */
809 string_prepend (decl, "ClassInfo for ");
810 string_setlength (decl, string_length (decl) - 1);
7e865541 811 mangled += len;
5cc158e9
IB
812 return mangled;
813 }
814 break;
815
816 case 10:
7e865541 817 if (strncmp (mangled, "__postblitMFZ", len+3) == 0)
5cc158e9
IB
818 {
819 /* Postblit symbol for a struct. */
820 string_append (decl, "this(this)");
7e865541 821 mangled += len + 3;
5cc158e9
IB
822 return mangled;
823 }
824 break;
825
826 case 11:
7e865541 827 if (strncmp (mangled, "__InterfaceZ", len+1) == 0)
5cc158e9
IB
828 {
829 /* The interface symbol for a given class. */
830 string_prepend (decl, "Interface for ");
831 string_setlength (decl, string_length (decl) - 1);
7e865541 832 mangled += len;
5cc158e9
IB
833 return mangled;
834 }
835 break;
836
837 case 12:
7e865541 838 if (strncmp (mangled, "__ModuleInfoZ", len+1) == 0)
5cc158e9
IB
839 {
840 /* The ModuleInfo symbol for a given module. */
841 string_prepend (decl, "ModuleInfo for ");
842 string_setlength (decl, string_length (decl) - 1);
7e865541 843 mangled += len;
5cc158e9
IB
844 return mangled;
845 }
846 break;
43b1b9ed
IB
847 }
848
7e865541
IB
849 string_appendn (decl, mangled, len);
850 mangled += len;
43b1b9ed 851 }
43b1b9ed
IB
852
853 return mangled;
854}
855
856/* Extract the integer value from MANGLED and append it to DECL,
857 where TYPE is the type it should be represented as.
858 Return the remaining string on success or NULL on failure. */
859static const char *
860dlang_parse_integer (string *decl, const char *mangled, char type)
861{
862 if (type == 'a' || type == 'u' || type == 'w')
863 {
864 /* Parse character value. */
865 char value[10];
866 int pos = 10;
867 int width = 0;
868 char *endptr;
869 long val = strtol (mangled, &endptr, 10);
870
871 if (endptr == NULL || val < 0)
872 return NULL;
873
874 string_append (decl, "'");
875
876 if (type == 'a' && val >= 0x20 && val < 0x7F)
877 {
878 /* Represent as a character literal. */
879 char c = (char) val;
880 string_appendn (decl, &c, 1);
881 }
882 else
883 {
884 /* Represent as a hexadecimal value. */
885 switch (type)
886 {
887 case 'a': /* char */
888 string_append (decl, "\\x");
889 width = 2;
890 break;
891 case 'u': /* wchar */
892 string_append (decl, "\\u");
893 width = 4;
894 break;
895 case 'w': /* dchar */
896 string_append (decl, "\\U");
897 width = 8;
898 break;
899 }
900
901 while (val > 0)
902 {
903 int digit = val % 16;
904
905 if (digit < 10)
906 value[--pos] = (char)(digit + '0');
907 else
908 value[--pos] = (char)((digit - 10) + 'a');
909
910 val /= 16;
911 width--;
912 }
913
914 for (; width > 0; width--)
915 value[--pos] = '0';
916
917 string_appendn (decl, &(value[pos]), 10 - pos);
918 }
919 string_append (decl, "'");
920 mangled = endptr;
921 }
922 else if (type == 'b')
923 {
924 /* Parse boolean value. */
925 char *endptr;
926 long val = strtol (mangled, &endptr, 10);
927
928 if (endptr == NULL || val < 0)
929 return NULL;
930
931 string_append (decl, val ? "true" : "false");
932 mangled = endptr;
933 }
934 else
935 {
936 /* Parse integer value. */
937 const char *numptr = mangled;
938 size_t num = 0;
939
940 while (ISDIGIT (*mangled))
941 {
942 num++;
943 mangled++;
944 }
945 string_appendn (decl, numptr, num);
946
947 /* Append suffix. */
948 switch (type)
949 {
950 case 'h': /* ubyte */
951 case 't': /* ushort */
952 case 'k': /* uint */
953 string_append (decl, "u");
954 break;
955 case 'l': /* long */
956 string_append (decl, "L");
957 break;
958 case 'm': /* ulong */
959 string_append (decl, "uL");
960 break;
961 }
962 }
963
964 return mangled;
965}
966
967/* Extract the floating-point value from MANGLED and append it to DECL.
968 Return the remaining string on success or NULL on failure. */
969static const char *
970dlang_parse_real (string *decl, const char *mangled)
971{
972 char buffer[64];
973 int len = 0;
43b1b9ed
IB
974
975 /* Handle NAN and +-INF. */
976 if (strncmp (mangled, "NAN", 3) == 0)
977 {
978 string_append (decl, "NaN");
979 mangled += 3;
980 return mangled;
981 }
982 else if (strncmp (mangled, "INF", 3) == 0)
983 {
984 string_append (decl, "Inf");
985 mangled += 3;
986 return mangled;
987 }
988 else if (strncmp (mangled, "NINF", 4) == 0)
989 {
990 string_append (decl, "-Inf");
991 mangled += 4;
992 return mangled;
993 }
994
995 /* Hexadecimal prefix and leading bit. */
996 if (*mangled == 'N')
997 {
998 buffer[len++] = '-';
999 mangled++;
1000 }
1001
1002 if (!ISXDIGIT (*mangled))
1003 return NULL;
1004
1005 buffer[len++] = '0';
1006 buffer[len++] = 'x';
1007 buffer[len++] = *mangled;
1008 buffer[len++] = '.';
1009 mangled++;
1010
1011 /* Significand. */
1012 while (ISXDIGIT (*mangled))
1013 {
1014 buffer[len++] = *mangled;
1015 mangled++;
1016 }
1017
1018 /* Exponent. */
1019 if (*mangled != 'P')
1020 return NULL;
1021
1022 buffer[len++] = 'p';
1023 mangled++;
1024
1025 if (*mangled == 'N')
1026 {
1027 buffer[len++] = '-';
1028 mangled++;
1029 }
1030
1031 while (ISDIGIT (*mangled))
1032 {
1033 buffer[len++] = *mangled;
1034 mangled++;
1035 }
1036
fd91ffb8
IB
1037 /* Write out the demangled hexadecimal, rather than trying to
1038 convert the buffer into a floating-point value. */
43b1b9ed 1039 buffer[len] = '\0';
fd91ffb8 1040 len = strlen (buffer);
43b1b9ed
IB
1041 string_appendn (decl, buffer, len);
1042 return mangled;
1043}
1044
1045/* Convert VAL from an ascii hexdigit to value. */
1046static char
1047ascii2hex (char val)
1048{
1049 if (val >= 'a' && val <= 'f')
1050 return (val - 'a' + 10);
1051
1052 if (val >= 'A' && val <= 'F')
1053 return (val - 'A' + 10);
1054
1055 if (val >= '0' && val <= '9')
1056 return (val - '0');
1057
1058 return 0;
1059}
1060
1061/* Extract the string value from MANGLED and append it to DECL.
1062 Return the remaining string on success or NULL on failure. */
1063static const char *
1064dlang_parse_string (string *decl, const char *mangled)
1065{
1066 char type = *mangled;
1067 char *endptr;
1068 long len;
1069
1070 mangled++;
1071 len = strtol (mangled, &endptr, 10);
1072
1073 if (endptr == NULL || len < 0)
1074 return NULL;
1075
1076 mangled = endptr;
1077 if (*mangled != '_')
1078 return NULL;
1079
1080 mangled++;
1081 string_append (decl, "\"");
1082 while (len--)
1083 {
1084 if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
1085 {
1086 char a = ascii2hex (mangled[0]);
1087 char b = ascii2hex (mangled[1]);
1088 char val = (a << 4) | b;
eb058b7d
IB
1089
1090 /* Sanitize white and non-printable characters. */
1091 switch (val)
1092 {
1093 case ' ':
1094 string_append (decl, " ");
1095 break;
1096 case '\t':
1097 string_append (decl, "\\t");
1098 break;
1099 case '\n':
1100 string_append (decl, "\\n");
1101 break;
1102 case '\r':
1103 string_append (decl, "\\r");
1104 break;
1105 case '\f':
1106 string_append (decl, "\\f");
1107 break;
1108 case '\v':
1109 string_append (decl, "\\v");
1110 break;
1111
1112 default:
1113 if (ISPRINT (val))
1114 string_appendn (decl, &val, 1);
1115 else
1116 {
1117 string_append (decl, "\\x");
1118 string_appendn (decl, mangled, 2);
1119 }
1120 }
43b1b9ed
IB
1121 }
1122 else
1123 return NULL;
1124
1125 mangled += 2;
1126 }
1127 string_append (decl, "\"");
1128
1129 if (type != 'a')
1130 string_appendn (decl, &type, 1);
1131
1132 return mangled;
1133}
1134
1135/* Extract the static array value from MANGLED and append it to DECL.
1136 Return the remaining string on success or NULL on failure. */
1137static const char *
1138dlang_parse_arrayliteral (string *decl, const char *mangled)
1139{
1140 char *endptr;
1141 long elements = strtol (mangled, &endptr, 10);
1142
1143 if (endptr == NULL || elements < 0)
1144 return NULL;
1145
1146 mangled = endptr;
1147 string_append (decl, "[");
1148 while (elements--)
1149 {
1150 mangled = dlang_value (decl, mangled, NULL, '\0');
1151 if (elements != 0)
1152 string_append (decl, ", ");
1153 }
1154
1155 string_append (decl, "]");
1156 return mangled;
1157}
1158
1159/* Extract the associative array value from MANGLED and append it to DECL.
1160 Return the remaining string on success or NULL on failure. */
1161static const char *
1162dlang_parse_assocarray (string *decl, const char *mangled)
1163{
1164 char *endptr;
1165 long elements = strtol (mangled, &endptr, 10);
1166
1167 if (endptr == NULL || elements < 0)
1168 return NULL;
1169
1170 mangled = endptr;
1171 string_append (decl, "[");
1172 while (elements--)
1173 {
1174 mangled = dlang_value (decl, mangled, NULL, '\0');
1175 string_append (decl, ":");
1176 mangled = dlang_value (decl, mangled, NULL, '\0');
1177
1178 if (elements != 0)
1179 string_append (decl, ", ");
1180 }
1181
1182 string_append (decl, "]");
1183 return mangled;
1184}
1185
1186/* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1187 Return the remaining string on success or NULL on failure. */
1188static const char *
1189dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1190{
1191 char *endptr;
1192 long args = strtol (mangled, &endptr, 10);
1193
1194 if (endptr == NULL || args < 0)
1195 return NULL;
1196
1197 mangled = endptr;
1198 if (name != NULL)
1199 string_append (decl, name);
1200
1201 string_append (decl, "(");
1202 while (args--)
1203 {
1204 mangled = dlang_value (decl, mangled, NULL, '\0');
1205 if (args != 0)
1206 string_append (decl, ", ");
1207 }
1208
1209 string_append (decl, ")");
1210 return mangled;
1211}
1212
1213/* Extract the value from MANGLED and append it to DECL.
1214 Return the remaining string on success or NULL on failure. */
1215static const char *
1216dlang_value (string *decl, const char *mangled, const char *name, char type)
1217{
1218 if (mangled == NULL || *mangled == '\0')
76b41cad 1219 return NULL;
43b1b9ed
IB
1220
1221 switch (*mangled)
1222 {
1223 /* Null value. */
1224 case 'n':
1225 mangled++;
1226 string_append (decl, "null");
1227 break;
1228
1229 /* Integral values. */
1230 case 'N':
1231 mangled++;
1232 string_append (decl, "-");
1233 mangled = dlang_parse_integer (decl, mangled, type);
1234 break;
1235
1236 case 'i':
1237 mangled++;
1238 if (*mangled < '0' || *mangled > '9')
1239 return NULL;
1240 /* Fall through */
1241 case '0': case '1': case '2': case '3': case '4':
1242 case '5': case '6': case '7': case '8': case '9':
1243 mangled = dlang_parse_integer (decl, mangled, type);
1244 break;
1245
1246 /* Real value. */
1247 case 'e':
1248 mangled++;
1249 mangled = dlang_parse_real (decl, mangled);
1250 break;
1251
1252 /* Complex value. */
1253 case 'c':
1254 mangled++;
1255 mangled = dlang_parse_real (decl, mangled);
1256 string_append (decl, "+");
1257 if (mangled == NULL || *mangled != 'c')
1258 return NULL;
1259 mangled++;
1260 mangled = dlang_parse_real (decl, mangled);
1261 string_append (decl, "i");
1262 break;
1263
1264 /* String values. */
1265 case 'a': /* UTF8 */
1266 case 'w': /* UTF16 */
1267 case 'd': /* UTF32 */
1268 mangled = dlang_parse_string (decl, mangled);
1269 break;
1270
1271 /* Array values. */
1272 case 'A':
1273 mangled++;
1274 if (type == 'H')
1275 mangled = dlang_parse_assocarray (decl, mangled);
1276 else
1277 mangled = dlang_parse_arrayliteral (decl, mangled);
1278 break;
1279
1280 /* Struct values. */
1281 case 'S':
1282 mangled++;
1283 mangled = dlang_parse_structlit (decl, mangled, name);
1284 break;
1285
1286 default:
1287 return NULL;
1288 }
1289
1290 return mangled;
1291}
1292
fa66ced4
IB
1293/* Extract the type modifiers from MANGLED and return the string
1294 length that it consumes in MANGLED on success or 0 on failure. */
43b1b9ed 1295static int
fa66ced4 1296dlang_type_modifier_p (const char *mangled)
43b1b9ed 1297{
fa66ced4 1298 int i;
43b1b9ed
IB
1299
1300 switch (*mangled)
1301 {
fa66ced4 1302 case 'x': case 'y':
43b1b9ed
IB
1303 return 1;
1304
fa66ced4
IB
1305 case 'O':
1306 mangled++;
1307 i = dlang_type_modifier_p (mangled);
1308 return i + 1;
43b1b9ed 1309
fa66ced4
IB
1310 case 'N':
1311 mangled++;
1312 if (*mangled == 'g')
43b1b9ed 1313 {
fa66ced4
IB
1314 mangled++;
1315 i = dlang_type_modifier_p (mangled);
1316 return i + 2;
43b1b9ed 1317 }
fa66ced4
IB
1318 }
1319
1320 return 0;
1321}
1322
1323/* Extract the function calling convention from MANGLED and
1324 return 1 on success or 0 on failure. */
1325static int
1326dlang_call_convention_p (const char *mangled)
1327{
1328 /* Prefix for functions needing 'this' */
1329 if (*mangled == 'M')
1330 {
1331 mangled++;
1332 /* Also skip over any type modifiers. */
1333 mangled += dlang_type_modifier_p (mangled);
1334 }
1335
1336 switch (*mangled)
1337 {
1338 case 'F': case 'U': case 'V':
1339 case 'W': case 'R':
1340 return 1;
43b1b9ed
IB
1341
1342 default:
1343 return 0;
1344 }
1345}
1346
1347/* Extract and demangle the symbol in MANGLED and append it to DECL.
1348 Returns the remaining signature on success or NULL on failure. */
1349static const char *
7e865541
IB
1350dlang_parse_symbol (string *decl, const char *mangled,
1351 enum dlang_symbol_kinds kind)
43b1b9ed 1352{
7e865541 1353 int saved;
43b1b9ed
IB
1354 size_t n = 0;
1355 do
1356 {
1357 if (n++)
1358 string_append (decl, ".");
1359
7e865541 1360 mangled = dlang_identifier (decl, mangled, kind);
43b1b9ed
IB
1361
1362 if (mangled && dlang_call_convention_p (mangled))
1363 {
fa66ced4 1364 string mods;
7e865541
IB
1365 const char *start = NULL;
1366 int checkpoint = 0;
43b1b9ed
IB
1367
1368 /* Skip over 'this' parameter. */
1369 if (*mangled == 'M')
fa66ced4
IB
1370 mangled++;
1371
7e865541
IB
1372 /* We have reached here because we expect an extern(Pascal) function.
1373 However this is so rare, that it is more likely a template value
1374 parameter. Since this can't be assumed, first attempt parsing
1375 the symbol as a function, and then back out on failure. */
1376 if (*mangled == 'V')
1377 {
1378 start = mangled;
1379 checkpoint = string_length (decl);
1380 }
1381
fa66ced4
IB
1382 /* Save the type modifiers for appending at the end. */
1383 string_init (&mods);
1384 mangled = dlang_type_modifiers (&mods, mangled);
43b1b9ed
IB
1385
1386 /* Skip over calling convention and attributes in qualified name. */
1387 saved = string_length (decl);
1388 mangled = dlang_call_convention (decl, mangled);
1389 mangled = dlang_attributes (decl, mangled);
1390 string_setlength (decl, saved);
1391
1392 string_append (decl, "(");
1393 mangled = dlang_function_args (decl, mangled);
1394 string_append (decl, ")");
1395
fa66ced4
IB
1396 /* Add any const/immutable/shared modifier. */
1397 string_appendn (decl, mods.b, string_length (&mods));
1398 string_delete (&mods);
7e865541
IB
1399
1400 if (mangled == NULL && checkpoint != 0)
1401 {
1402 mangled = start;
1403 string_setlength (decl, checkpoint);
1404 }
43b1b9ed
IB
1405 }
1406 }
1407 while (mangled && ISDIGIT (*mangled));
1408
7e865541
IB
1409 /* Only top-level symbols or function template parameters have
1410 a type that needs checking. */
1411 if (kind == dlang_top_level || kind == dlang_function)
1412 {
1413 /* Artificial symbols end with 'Z' and have no type. */
1414 if (mangled && *mangled == 'Z')
1415 mangled++;
1416 else
1417 {
1418 saved = string_length (decl);
1419 mangled = dlang_type (decl, mangled);
1420 string_setlength (decl, saved);
1421 }
1422
1423 /* Check that the entire symbol was successfully demangled. */
1424 if (kind == dlang_top_level)
1425 {
1426 if (mangled == NULL || *mangled != '\0')
1427 return NULL;
1428 }
1429 }
1430
43b1b9ed
IB
1431 return mangled;
1432}
1433
1434/* Demangle the tuple from MANGLED and append it to DECL.
1435 Return the remaining string on success or NULL on failure. */
1436static const char *
1437dlang_parse_tuple (string *decl, const char *mangled)
1438{
1439 char *endptr;
1440 long elements = strtol (mangled, &endptr, 10);
1441
1442 if (endptr == NULL || elements < 0)
1443 return NULL;
1444
1445 mangled = endptr;
1446 string_append (decl, "Tuple!(");
1447
1448 while (elements--)
1449 {
1450 mangled = dlang_type (decl, mangled);
1451 if (elements != 0)
1452 string_append (decl, ", ");
1453 }
1454
1455 string_append (decl, ")");
1456 return mangled;
1457}
1458
1459/* Demangle the argument list from MANGLED and append it to DECL.
1460 Return the remaining string on success or NULL on failure. */
1461static const char *
1462dlang_template_args (string *decl, const char *mangled)
1463{
1464 size_t n = 0;
1465
1466 while (mangled && *mangled != '\0')
1467 {
1468 switch (*mangled)
1469 {
1470 case 'Z': /* End of parameter list. */
1471 mangled++;
1472 return mangled;
1473 }
1474
1475 if (n++)
1476 string_append (decl, ", ");
1477
ed4cdb85
IB
1478 /* Skip over specialised template prefix. */
1479 if (*mangled == 'H')
1480 mangled++;
1481
43b1b9ed
IB
1482 switch (*mangled)
1483 {
1484 case 'S': /* Symbol parameter. */
1485 mangled++;
7e865541 1486 mangled = dlang_parse_symbol (decl, mangled, dlang_template_param);
43b1b9ed
IB
1487 break;
1488 case 'T': /* Type parameter. */
1489 mangled++;
1490 mangled = dlang_type (decl, mangled);
1491 break;
1492 case 'V': /* Value parameter. */
1493 {
1494 string name;
1495 char type;
1496
1497 /* Peek at the type. */
1498 mangled++;
1499 type = *mangled;
1500
1501 /* In the few instances where the type is actually desired in
1502 the output, it should precede the value from dlang_value. */
1503 string_init (&name);
1504 mangled = dlang_type (&name, mangled);
1505 string_need (&name, 1);
1506 *(name.p) = '\0';
1507
1508 mangled = dlang_value (decl, mangled, name.b, type);
1509 string_delete (&name);
1510 break;
1511 }
1512
1513 default:
1514 return NULL;
1515 }
1516 }
1517
1518 return mangled;
1519}
1520
1521/* Extract and demangle the template symbol in MANGLED, expected to
1522 be made up of LEN characters, and append it to DECL.
1523 Returns the remaining signature on success or NULL on failure. */
1524static const char *
1525dlang_parse_template (string *decl, const char *mangled, long len)
1526{
1527 const char *start = mangled;
1528
1529 /* Template instance names have the types and values of its parameters
1530 encoded into it.
1531
1532 TemplateInstanceName:
1533 Number __T LName TemplateArgs Z
1534 ^
1535 The start pointer should be at the above location, and LEN should be
1536 the value of the decoded number.
1537 */
1538 if (strncmp (mangled, "__T", 3) != 0)
1539 return NULL;
1540
1541 mangled += 3;
1542
1543 /* Template identifier. */
7e865541 1544 mangled = dlang_identifier (decl, mangled, dlang_template_ident);
43b1b9ed
IB
1545
1546 /* Template arguments. */
1547 string_append (decl, "!(");
1548 mangled = dlang_template_args (decl, mangled);
1549 string_append (decl, ")");
1550
1551 /* Check for template name length mismatch. */
1552 if (mangled && (mangled - start) != len)
1553 return NULL;
1554
1555 return mangled;
1556}
1557
1558/* Extract and demangle the symbol in MANGLED. Returns the demangled
1559 signature on success or NULL on failure. */
1560
1561char *
1562dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1563{
1564 string decl;
1565 char *demangled = NULL;
1566
1567 if (mangled == NULL || *mangled == '\0')
1568 return NULL;
1569
1570 if (strncmp (mangled, "_D", 2) != 0)
1571 return NULL;
1572
1573 string_init (&decl);
1574
1575 if (strcmp (mangled, "_Dmain") == 0)
1576 {
1577 string_append (&decl, "D main");
1578 }
1579 else
1580 {
1581 mangled += 2;
1582
7e865541 1583 if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL)
43b1b9ed
IB
1584 string_delete (&decl);
1585 }
1586
1587 if (string_length (&decl) > 0)
1588 {
1589 string_need (&decl, 1);
1590 *(decl.p) = '\0';
1591 demangled = decl.b;
1592 }
1593
1594 return demangled;
1595}
1596