]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/d-demangle.c
d-demangle.c (dlang_function_args): Append ',' for variadic functions only if paramet...
[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++;
acf1f7da
IB
402 if (n != 0)
403 string_append (decl, ", ");
404 string_append (decl, "...");
43b1b9ed
IB
405 return mangled;
406 case 'Z': /* Normal function. */
407 mangled++;
408 return mangled;
409 }
410
411 if (n++)
412 string_append (decl, ", ");
413
414 if (*mangled == 'M') /* scope(T) */
415 {
416 mangled++;
417 string_append (decl, "scope ");
418 }
419
7ce4461f
IB
420 if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */
421 {
422 mangled += 2;
423 string_append (decl, "return ");
424 }
425
43b1b9ed
IB
426 switch (*mangled)
427 {
428 case 'J': /* out(T) */
429 mangled++;
430 string_append (decl, "out ");
431 break;
432 case 'K': /* ref(T) */
433 mangled++;
434 string_append (decl, "ref ");
435 break;
436 case 'L': /* lazy(T) */
437 mangled++;
438 string_append (decl, "lazy ");
439 break;
440 }
441 mangled = dlang_type (decl, mangled);
442 }
443
444 return mangled;
445}
446
447/* Demangle the type from MANGLED and append it to DECL.
448 Return the remaining string on success or NULL on failure. */
449static const char *
450dlang_type (string *decl, const char *mangled)
451{
452 if (mangled == NULL || *mangled == '\0')
76b41cad 453 return NULL;
43b1b9ed
IB
454
455 switch (*mangled)
456 {
457 case 'O': /* shared(T) */
458 mangled++;
459 string_append (decl, "shared(");
460 mangled = dlang_type (decl, mangled);
461 string_append (decl, ")");
462 return mangled;
463 case 'x': /* const(T) */
464 mangled++;
465 string_append (decl, "const(");
466 mangled = dlang_type (decl, mangled);
467 string_append (decl, ")");
468 return mangled;
469 case 'y': /* immutable(T) */
470 mangled++;
471 string_append (decl, "immutable(");
472 mangled = dlang_type (decl, mangled);
473 string_append (decl, ")");
474 return mangled;
475 case 'N':
476 mangled++;
477 if (*mangled == 'g') /* wild(T) */
478 {
479 mangled++;
480 string_append (decl, "inout(");
481 mangled = dlang_type (decl, mangled);
482 string_append (decl, ")");
483 return mangled;
484 }
485 else if (*mangled == 'h') /* vector(T) */
486 {
487 mangled++;
488 string_append (decl, "__vector(");
489 mangled = dlang_type (decl, mangled);
490 string_append (decl, ")");
491 return mangled;
492 }
493 else
494 return NULL;
495 case 'A': /* dynamic array (T[]) */
496 mangled++;
497 mangled = dlang_type (decl, mangled);
498 string_append (decl, "[]");
499 return mangled;
500 case 'G': /* static array (T[N]) */
501 {
502 const char *numptr;
503 size_t num = 0;
504 mangled++;
505
506 numptr = mangled;
507 while (ISDIGIT (*mangled))
508 {
509 num++;
510 mangled++;
511 }
512 mangled = dlang_type (decl, mangled);
513 string_append (decl, "[");
514 string_appendn (decl, numptr, num);
515 string_append (decl, "]");
516 return mangled;
517 }
518 case 'H': /* associative array (T[T]) */
519 {
520 string type;
521 size_t sztype;
522 mangled++;
523
524 string_init (&type);
525 mangled = dlang_type (&type, mangled);
526 sztype = string_length (&type);
527
528 mangled = dlang_type (decl, mangled);
529 string_append (decl, "[");
530 string_appendn (decl, type.b, sztype);
531 string_append (decl, "]");
532
533 string_delete (&type);
534 return mangled;
535 }
536 case 'P': /* pointer (T*) */
537 mangled++;
0f4b8b31
IB
538 /* Function pointer types don't include the trailing asterisk. */
539 switch (*mangled)
540 {
541 case 'F': case 'U': case 'W':
542 case 'V': case 'R':
543 mangled = dlang_function_type (decl, mangled);
544 string_append (decl, "function");
545 return mangled;
546 }
43b1b9ed
IB
547 mangled = dlang_type (decl, mangled);
548 string_append (decl, "*");
549 return mangled;
550 case 'I': /* ident T */
551 case 'C': /* class T */
552 case 'S': /* struct T */
553 case 'E': /* enum T */
554 case 'T': /* typedef T */
555 mangled++;
7e865541 556 return dlang_parse_symbol (decl, mangled, dlang_type_name);
43b1b9ed 557 case 'D': /* delegate T */
fa66ced4
IB
558 {
559 string mods;
560 size_t szmods;
43b1b9ed 561 mangled++;
fa66ced4
IB
562
563 string_init (&mods);
564 mangled = dlang_type_modifiers (&mods, mangled);
565 szmods = string_length (&mods);
566
43b1b9ed
IB
567 mangled = dlang_function_type (decl, mangled);
568 string_append (decl, "delegate");
fa66ced4
IB
569 string_appendn (decl, mods.b, szmods);
570
571 string_delete (&mods);
43b1b9ed 572 return mangled;
fa66ced4 573 }
43b1b9ed
IB
574 case 'B': /* tuple T */
575 mangled++;
576 return dlang_parse_tuple (decl, mangled);
577
43b1b9ed
IB
578 /* Basic types */
579 case 'n':
580 mangled++;
581 string_append (decl, "none");
582 return mangled;
583 case 'v':
584 mangled++;
585 string_append (decl, "void");
586 return mangled;
587 case 'g':
588 mangled++;
589 string_append (decl, "byte");
590 return mangled;
591 case 'h':
592 mangled++;
593 string_append (decl, "ubyte");
594 return mangled;
595 case 's':
596 mangled++;
597 string_append (decl, "short");
598 return mangled;
599 case 't':
600 mangled++;
601 string_append (decl, "ushort");
602 return mangled;
603 case 'i':
604 mangled++;
605 string_append (decl, "int");
606 return mangled;
607 case 'k':
608 mangled++;
609 string_append (decl, "uint");
610 return mangled;
611 case 'l':
612 mangled++;
613 string_append (decl, "long");
614 return mangled;
615 case 'm':
616 mangled++;
617 string_append (decl, "ulong");
618 return mangled;
619 case 'f':
620 mangled++;
621 string_append (decl, "float");
622 return mangled;
623 case 'd':
624 mangled++;
625 string_append (decl, "double");
626 return mangled;
627 case 'e':
628 mangled++;
629 string_append (decl, "real");
630 return mangled;
631
632 /* Imaginary and Complex types */
633 case 'o':
634 mangled++;
635 string_append (decl, "ifloat");
636 return mangled;
637 case 'p':
638 mangled++;
639 string_append (decl, "idouble");
640 return mangled;
641 case 'j':
642 mangled++;
643 string_append (decl, "ireal");
644 return mangled;
645 case 'q':
646 mangled++;
647 string_append (decl, "cfloat");
648 return mangled;
649 case 'r':
650 mangled++;
651 string_append (decl, "cdouble");
652 return mangled;
653 case 'c':
654 mangled++;
655 string_append (decl, "creal");
656 return mangled;
657
658 /* Other types */
659 case 'b':
660 mangled++;
661 string_append (decl, "bool");
662 return mangled;
663 case 'a':
664 mangled++;
665 string_append (decl, "char");
666 return mangled;
667 case 'u':
668 mangled++;
669 string_append (decl, "wchar");
670 return mangled;
671 case 'w':
672 mangled++;
673 string_append (decl, "dchar");
674 return mangled;
59251a73
IB
675 case 'z':
676 mangled++;
677 switch (*mangled)
678 {
679 case 'i':
680 mangled++;
681 string_append (decl, "cent");
682 return mangled;
683 case 'k':
684 mangled++;
685 string_append (decl, "ucent");
686 return mangled;
687 }
688 return NULL;
43b1b9ed
IB
689
690 default: /* unhandled */
691 return NULL;
692 }
693}
694
695/* Extract the identifier from MANGLED and append it to DECL.
696 Return the remaining string on success or NULL on failure. */
697static const char *
7e865541
IB
698dlang_identifier (string *decl, const char *mangled,
699 enum dlang_symbol_kinds kind)
43b1b9ed 700{
7e865541
IB
701 char *endptr;
702 long len;
703
43b1b9ed 704 if (mangled == NULL || *mangled == '\0')
76b41cad 705 return NULL;
43b1b9ed 706
7e865541
IB
707 len = strtol (mangled, &endptr, 10);
708
709 if (endptr == NULL || len <= 0)
710 return NULL;
711
712 /* In template parameter symbols, the first character of the mangled
713 name can be a digit. This causes ambiguity issues because the
714 digits of the two numbers are adjacent. */
715 if (kind == dlang_template_param)
43b1b9ed 716 {
7e865541
IB
717 long psize = len;
718 char *pend;
719 int saved = string_length (decl);
720
721 /* Work backwards until a match is found. */
722 for (pend = endptr; endptr != NULL; pend--)
723 {
724 mangled = pend;
43b1b9ed 725
7e865541
IB
726 /* Reached the beginning of the pointer to the name length,
727 try parsing the entire symbol. */
728 if (psize == 0)
729 {
730 psize = len;
731 pend = endptr;
732 endptr = NULL;
733 }
734
735 /* Check whether template parameter is a function with a valid
736 return type or an untyped identifier. */
737 if (ISDIGIT (*mangled))
738 mangled = dlang_parse_symbol (decl, mangled, dlang_template_ident);
739 else if (strncmp (mangled, "_D", 2) == 0)
740 {
741 mangled += 2;
742 mangled = dlang_parse_symbol (decl, mangled, dlang_function);
743 }
744
745 /* Check for name length mismatch. */
746 if (mangled && (mangled - pend) == psize)
747 return mangled;
748
749 psize /= 10;
750 string_setlength (decl, saved);
751 }
752
753 /* No match on any combinations. */
754 return NULL;
755 }
756 else
757 {
758 if (strlen (endptr) < (size_t) len)
43b1b9ed
IB
759 return NULL;
760
761 mangled = endptr;
762
763 /* May be a template instance. */
7e865541 764 if (len >= 5 && strncmp (mangled, "__T", 3) == 0)
43b1b9ed
IB
765 {
766 /* Template symbol. */
767 if (ISDIGIT (mangled[3]) && mangled[3] != '0')
7e865541 768 return dlang_parse_template (decl, mangled, len);
43b1b9ed
IB
769
770 return NULL;
771 }
772
7e865541 773 switch (len)
43b1b9ed 774 {
5cc158e9 775 case 6:
7e865541 776 if (strncmp (mangled, "__ctor", len) == 0)
5cc158e9
IB
777 {
778 /* Constructor symbol for a class/struct. */
779 string_append (decl, "this");
7e865541 780 mangled += len;
5cc158e9
IB
781 return mangled;
782 }
7e865541 783 else if (strncmp (mangled, "__dtor", len) == 0)
5cc158e9
IB
784 {
785 /* Destructor symbol for a class/struct. */
786 string_append (decl, "~this");
7e865541 787 mangled += len;
5cc158e9
IB
788 return mangled;
789 }
7e865541 790 else if (strncmp (mangled, "__initZ", len+1) == 0)
5cc158e9
IB
791 {
792 /* The static initialiser for a given symbol. */
793 string_append (decl, "init$");
7e865541 794 mangled += len;
5cc158e9
IB
795 return mangled;
796 }
7e865541 797 else if (strncmp (mangled, "__vtblZ", len+1) == 0)
5cc158e9
IB
798 {
799 /* The vtable symbol for a given class. */
800 string_prepend (decl, "vtable for ");
801 string_setlength (decl, string_length (decl) - 1);
7e865541 802 mangled += len;
5cc158e9
IB
803 return mangled;
804 }
805 break;
806
807 case 7:
7e865541 808 if (strncmp (mangled, "__ClassZ", len+1) == 0)
5cc158e9
IB
809 {
810 /* The classinfo symbol for a given class. */
811 string_prepend (decl, "ClassInfo for ");
812 string_setlength (decl, string_length (decl) - 1);
7e865541 813 mangled += len;
5cc158e9
IB
814 return mangled;
815 }
816 break;
817
818 case 10:
7e865541 819 if (strncmp (mangled, "__postblitMFZ", len+3) == 0)
5cc158e9
IB
820 {
821 /* Postblit symbol for a struct. */
822 string_append (decl, "this(this)");
7e865541 823 mangled += len + 3;
5cc158e9
IB
824 return mangled;
825 }
826 break;
827
828 case 11:
7e865541 829 if (strncmp (mangled, "__InterfaceZ", len+1) == 0)
5cc158e9
IB
830 {
831 /* The interface symbol for a given class. */
832 string_prepend (decl, "Interface for ");
833 string_setlength (decl, string_length (decl) - 1);
7e865541 834 mangled += len;
5cc158e9
IB
835 return mangled;
836 }
837 break;
838
839 case 12:
7e865541 840 if (strncmp (mangled, "__ModuleInfoZ", len+1) == 0)
5cc158e9
IB
841 {
842 /* The ModuleInfo symbol for a given module. */
843 string_prepend (decl, "ModuleInfo for ");
844 string_setlength (decl, string_length (decl) - 1);
7e865541 845 mangled += len;
5cc158e9
IB
846 return mangled;
847 }
848 break;
43b1b9ed
IB
849 }
850
7e865541
IB
851 string_appendn (decl, mangled, len);
852 mangled += len;
43b1b9ed 853 }
43b1b9ed
IB
854
855 return mangled;
856}
857
858/* Extract the integer value from MANGLED and append it to DECL,
859 where TYPE is the type it should be represented as.
860 Return the remaining string on success or NULL on failure. */
861static const char *
862dlang_parse_integer (string *decl, const char *mangled, char type)
863{
864 if (type == 'a' || type == 'u' || type == 'w')
865 {
866 /* Parse character value. */
867 char value[10];
868 int pos = 10;
869 int width = 0;
870 char *endptr;
871 long val = strtol (mangled, &endptr, 10);
872
873 if (endptr == NULL || val < 0)
874 return NULL;
875
876 string_append (decl, "'");
877
878 if (type == 'a' && val >= 0x20 && val < 0x7F)
879 {
880 /* Represent as a character literal. */
881 char c = (char) val;
882 string_appendn (decl, &c, 1);
883 }
884 else
885 {
886 /* Represent as a hexadecimal value. */
887 switch (type)
888 {
889 case 'a': /* char */
890 string_append (decl, "\\x");
891 width = 2;
892 break;
893 case 'u': /* wchar */
894 string_append (decl, "\\u");
895 width = 4;
896 break;
897 case 'w': /* dchar */
898 string_append (decl, "\\U");
899 width = 8;
900 break;
901 }
902
903 while (val > 0)
904 {
905 int digit = val % 16;
906
907 if (digit < 10)
908 value[--pos] = (char)(digit + '0');
909 else
910 value[--pos] = (char)((digit - 10) + 'a');
911
912 val /= 16;
913 width--;
914 }
915
916 for (; width > 0; width--)
917 value[--pos] = '0';
918
919 string_appendn (decl, &(value[pos]), 10 - pos);
920 }
921 string_append (decl, "'");
922 mangled = endptr;
923 }
924 else if (type == 'b')
925 {
926 /* Parse boolean value. */
927 char *endptr;
928 long val = strtol (mangled, &endptr, 10);
929
930 if (endptr == NULL || val < 0)
931 return NULL;
932
933 string_append (decl, val ? "true" : "false");
934 mangled = endptr;
935 }
936 else
937 {
938 /* Parse integer value. */
939 const char *numptr = mangled;
940 size_t num = 0;
941
942 while (ISDIGIT (*mangled))
943 {
944 num++;
945 mangled++;
946 }
947 string_appendn (decl, numptr, num);
948
949 /* Append suffix. */
950 switch (type)
951 {
952 case 'h': /* ubyte */
953 case 't': /* ushort */
954 case 'k': /* uint */
955 string_append (decl, "u");
956 break;
957 case 'l': /* long */
958 string_append (decl, "L");
959 break;
960 case 'm': /* ulong */
961 string_append (decl, "uL");
962 break;
963 }
964 }
965
966 return mangled;
967}
968
969/* Extract the floating-point value from MANGLED and append it to DECL.
970 Return the remaining string on success or NULL on failure. */
971static const char *
972dlang_parse_real (string *decl, const char *mangled)
973{
974 char buffer[64];
975 int len = 0;
43b1b9ed
IB
976
977 /* Handle NAN and +-INF. */
978 if (strncmp (mangled, "NAN", 3) == 0)
979 {
980 string_append (decl, "NaN");
981 mangled += 3;
982 return mangled;
983 }
984 else if (strncmp (mangled, "INF", 3) == 0)
985 {
986 string_append (decl, "Inf");
987 mangled += 3;
988 return mangled;
989 }
990 else if (strncmp (mangled, "NINF", 4) == 0)
991 {
992 string_append (decl, "-Inf");
993 mangled += 4;
994 return mangled;
995 }
996
997 /* Hexadecimal prefix and leading bit. */
998 if (*mangled == 'N')
999 {
1000 buffer[len++] = '-';
1001 mangled++;
1002 }
1003
1004 if (!ISXDIGIT (*mangled))
1005 return NULL;
1006
1007 buffer[len++] = '0';
1008 buffer[len++] = 'x';
1009 buffer[len++] = *mangled;
1010 buffer[len++] = '.';
1011 mangled++;
1012
1013 /* Significand. */
1014 while (ISXDIGIT (*mangled))
1015 {
1016 buffer[len++] = *mangled;
1017 mangled++;
1018 }
1019
1020 /* Exponent. */
1021 if (*mangled != 'P')
1022 return NULL;
1023
1024 buffer[len++] = 'p';
1025 mangled++;
1026
1027 if (*mangled == 'N')
1028 {
1029 buffer[len++] = '-';
1030 mangled++;
1031 }
1032
1033 while (ISDIGIT (*mangled))
1034 {
1035 buffer[len++] = *mangled;
1036 mangled++;
1037 }
1038
fd91ffb8
IB
1039 /* Write out the demangled hexadecimal, rather than trying to
1040 convert the buffer into a floating-point value. */
43b1b9ed 1041 buffer[len] = '\0';
fd91ffb8 1042 len = strlen (buffer);
43b1b9ed
IB
1043 string_appendn (decl, buffer, len);
1044 return mangled;
1045}
1046
1047/* Convert VAL from an ascii hexdigit to value. */
1048static char
1049ascii2hex (char val)
1050{
1051 if (val >= 'a' && val <= 'f')
1052 return (val - 'a' + 10);
1053
1054 if (val >= 'A' && val <= 'F')
1055 return (val - 'A' + 10);
1056
1057 if (val >= '0' && val <= '9')
1058 return (val - '0');
1059
1060 return 0;
1061}
1062
1063/* Extract the string value from MANGLED and append it to DECL.
1064 Return the remaining string on success or NULL on failure. */
1065static const char *
1066dlang_parse_string (string *decl, const char *mangled)
1067{
1068 char type = *mangled;
1069 char *endptr;
1070 long len;
1071
1072 mangled++;
1073 len = strtol (mangled, &endptr, 10);
1074
1075 if (endptr == NULL || len < 0)
1076 return NULL;
1077
1078 mangled = endptr;
1079 if (*mangled != '_')
1080 return NULL;
1081
1082 mangled++;
1083 string_append (decl, "\"");
1084 while (len--)
1085 {
1086 if (ISXDIGIT (mangled[0]) && ISXDIGIT (mangled[1]))
1087 {
1088 char a = ascii2hex (mangled[0]);
1089 char b = ascii2hex (mangled[1]);
1090 char val = (a << 4) | b;
eb058b7d
IB
1091
1092 /* Sanitize white and non-printable characters. */
1093 switch (val)
1094 {
1095 case ' ':
1096 string_append (decl, " ");
1097 break;
1098 case '\t':
1099 string_append (decl, "\\t");
1100 break;
1101 case '\n':
1102 string_append (decl, "\\n");
1103 break;
1104 case '\r':
1105 string_append (decl, "\\r");
1106 break;
1107 case '\f':
1108 string_append (decl, "\\f");
1109 break;
1110 case '\v':
1111 string_append (decl, "\\v");
1112 break;
1113
1114 default:
1115 if (ISPRINT (val))
1116 string_appendn (decl, &val, 1);
1117 else
1118 {
1119 string_append (decl, "\\x");
1120 string_appendn (decl, mangled, 2);
1121 }
1122 }
43b1b9ed
IB
1123 }
1124 else
1125 return NULL;
1126
1127 mangled += 2;
1128 }
1129 string_append (decl, "\"");
1130
1131 if (type != 'a')
1132 string_appendn (decl, &type, 1);
1133
1134 return mangled;
1135}
1136
1137/* Extract the static array value from MANGLED and append it to DECL.
1138 Return the remaining string on success or NULL on failure. */
1139static const char *
1140dlang_parse_arrayliteral (string *decl, const char *mangled)
1141{
1142 char *endptr;
1143 long elements = strtol (mangled, &endptr, 10);
1144
1145 if (endptr == NULL || elements < 0)
1146 return NULL;
1147
1148 mangled = endptr;
1149 string_append (decl, "[");
1150 while (elements--)
1151 {
1152 mangled = dlang_value (decl, mangled, NULL, '\0');
1153 if (elements != 0)
1154 string_append (decl, ", ");
1155 }
1156
1157 string_append (decl, "]");
1158 return mangled;
1159}
1160
1161/* Extract the associative array value from MANGLED and append it to DECL.
1162 Return the remaining string on success or NULL on failure. */
1163static const char *
1164dlang_parse_assocarray (string *decl, const char *mangled)
1165{
1166 char *endptr;
1167 long elements = strtol (mangled, &endptr, 10);
1168
1169 if (endptr == NULL || elements < 0)
1170 return NULL;
1171
1172 mangled = endptr;
1173 string_append (decl, "[");
1174 while (elements--)
1175 {
1176 mangled = dlang_value (decl, mangled, NULL, '\0');
1177 string_append (decl, ":");
1178 mangled = dlang_value (decl, mangled, NULL, '\0');
1179
1180 if (elements != 0)
1181 string_append (decl, ", ");
1182 }
1183
1184 string_append (decl, "]");
1185 return mangled;
1186}
1187
1188/* Extract the struct literal value for NAME from MANGLED and append it to DECL.
1189 Return the remaining string on success or NULL on failure. */
1190static const char *
1191dlang_parse_structlit (string *decl, const char *mangled, const char *name)
1192{
1193 char *endptr;
1194 long args = strtol (mangled, &endptr, 10);
1195
1196 if (endptr == NULL || args < 0)
1197 return NULL;
1198
1199 mangled = endptr;
1200 if (name != NULL)
1201 string_append (decl, name);
1202
1203 string_append (decl, "(");
1204 while (args--)
1205 {
1206 mangled = dlang_value (decl, mangled, NULL, '\0');
1207 if (args != 0)
1208 string_append (decl, ", ");
1209 }
1210
1211 string_append (decl, ")");
1212 return mangled;
1213}
1214
1215/* Extract the value from MANGLED and append it to DECL.
1216 Return the remaining string on success or NULL on failure. */
1217static const char *
1218dlang_value (string *decl, const char *mangled, const char *name, char type)
1219{
1220 if (mangled == NULL || *mangled == '\0')
76b41cad 1221 return NULL;
43b1b9ed
IB
1222
1223 switch (*mangled)
1224 {
1225 /* Null value. */
1226 case 'n':
1227 mangled++;
1228 string_append (decl, "null");
1229 break;
1230
1231 /* Integral values. */
1232 case 'N':
1233 mangled++;
1234 string_append (decl, "-");
1235 mangled = dlang_parse_integer (decl, mangled, type);
1236 break;
1237
1238 case 'i':
1239 mangled++;
1240 if (*mangled < '0' || *mangled > '9')
1241 return NULL;
1242 /* Fall through */
1243 case '0': case '1': case '2': case '3': case '4':
1244 case '5': case '6': case '7': case '8': case '9':
1245 mangled = dlang_parse_integer (decl, mangled, type);
1246 break;
1247
1248 /* Real value. */
1249 case 'e':
1250 mangled++;
1251 mangled = dlang_parse_real (decl, mangled);
1252 break;
1253
1254 /* Complex value. */
1255 case 'c':
1256 mangled++;
1257 mangled = dlang_parse_real (decl, mangled);
1258 string_append (decl, "+");
1259 if (mangled == NULL || *mangled != 'c')
1260 return NULL;
1261 mangled++;
1262 mangled = dlang_parse_real (decl, mangled);
1263 string_append (decl, "i");
1264 break;
1265
1266 /* String values. */
1267 case 'a': /* UTF8 */
1268 case 'w': /* UTF16 */
1269 case 'd': /* UTF32 */
1270 mangled = dlang_parse_string (decl, mangled);
1271 break;
1272
1273 /* Array values. */
1274 case 'A':
1275 mangled++;
1276 if (type == 'H')
1277 mangled = dlang_parse_assocarray (decl, mangled);
1278 else
1279 mangled = dlang_parse_arrayliteral (decl, mangled);
1280 break;
1281
1282 /* Struct values. */
1283 case 'S':
1284 mangled++;
1285 mangled = dlang_parse_structlit (decl, mangled, name);
1286 break;
1287
1288 default:
1289 return NULL;
1290 }
1291
1292 return mangled;
1293}
1294
fa66ced4
IB
1295/* Extract the type modifiers from MANGLED and return the string
1296 length that it consumes in MANGLED on success or 0 on failure. */
43b1b9ed 1297static int
fa66ced4 1298dlang_type_modifier_p (const char *mangled)
43b1b9ed 1299{
fa66ced4 1300 int i;
43b1b9ed
IB
1301
1302 switch (*mangled)
1303 {
fa66ced4 1304 case 'x': case 'y':
43b1b9ed
IB
1305 return 1;
1306
fa66ced4
IB
1307 case 'O':
1308 mangled++;
1309 i = dlang_type_modifier_p (mangled);
1310 return i + 1;
43b1b9ed 1311
fa66ced4
IB
1312 case 'N':
1313 mangled++;
1314 if (*mangled == 'g')
43b1b9ed 1315 {
fa66ced4
IB
1316 mangled++;
1317 i = dlang_type_modifier_p (mangled);
1318 return i + 2;
43b1b9ed 1319 }
fa66ced4
IB
1320 }
1321
1322 return 0;
1323}
1324
1325/* Extract the function calling convention from MANGLED and
1326 return 1 on success or 0 on failure. */
1327static int
1328dlang_call_convention_p (const char *mangled)
1329{
1330 /* Prefix for functions needing 'this' */
1331 if (*mangled == 'M')
1332 {
1333 mangled++;
1334 /* Also skip over any type modifiers. */
1335 mangled += dlang_type_modifier_p (mangled);
1336 }
1337
1338 switch (*mangled)
1339 {
1340 case 'F': case 'U': case 'V':
1341 case 'W': case 'R':
1342 return 1;
43b1b9ed
IB
1343
1344 default:
1345 return 0;
1346 }
1347}
1348
1349/* Extract and demangle the symbol in MANGLED and append it to DECL.
1350 Returns the remaining signature on success or NULL on failure. */
1351static const char *
7e865541
IB
1352dlang_parse_symbol (string *decl, const char *mangled,
1353 enum dlang_symbol_kinds kind)
43b1b9ed 1354{
7e865541 1355 int saved;
43b1b9ed
IB
1356 size_t n = 0;
1357 do
1358 {
1359 if (n++)
1360 string_append (decl, ".");
1361
7e865541 1362 mangled = dlang_identifier (decl, mangled, kind);
43b1b9ed
IB
1363
1364 if (mangled && dlang_call_convention_p (mangled))
1365 {
fa66ced4 1366 string mods;
7e865541
IB
1367 const char *start = NULL;
1368 int checkpoint = 0;
43b1b9ed
IB
1369
1370 /* Skip over 'this' parameter. */
1371 if (*mangled == 'M')
fa66ced4
IB
1372 mangled++;
1373
7e865541
IB
1374 /* We have reached here because we expect an extern(Pascal) function.
1375 However this is so rare, that it is more likely a template value
1376 parameter. Since this can't be assumed, first attempt parsing
1377 the symbol as a function, and then back out on failure. */
1378 if (*mangled == 'V')
1379 {
1380 start = mangled;
1381 checkpoint = string_length (decl);
1382 }
1383
fa66ced4
IB
1384 /* Save the type modifiers for appending at the end. */
1385 string_init (&mods);
1386 mangled = dlang_type_modifiers (&mods, mangled);
43b1b9ed
IB
1387
1388 /* Skip over calling convention and attributes in qualified name. */
1389 saved = string_length (decl);
1390 mangled = dlang_call_convention (decl, mangled);
1391 mangled = dlang_attributes (decl, mangled);
1392 string_setlength (decl, saved);
1393
1394 string_append (decl, "(");
1395 mangled = dlang_function_args (decl, mangled);
1396 string_append (decl, ")");
1397
fa66ced4
IB
1398 /* Add any const/immutable/shared modifier. */
1399 string_appendn (decl, mods.b, string_length (&mods));
1400 string_delete (&mods);
7e865541
IB
1401
1402 if (mangled == NULL && checkpoint != 0)
1403 {
1404 mangled = start;
1405 string_setlength (decl, checkpoint);
1406 }
43b1b9ed
IB
1407 }
1408 }
1409 while (mangled && ISDIGIT (*mangled));
1410
7e865541
IB
1411 /* Only top-level symbols or function template parameters have
1412 a type that needs checking. */
1413 if (kind == dlang_top_level || kind == dlang_function)
1414 {
1415 /* Artificial symbols end with 'Z' and have no type. */
1416 if (mangled && *mangled == 'Z')
1417 mangled++;
1418 else
1419 {
1420 saved = string_length (decl);
1421 mangled = dlang_type (decl, mangled);
1422 string_setlength (decl, saved);
1423 }
1424
1425 /* Check that the entire symbol was successfully demangled. */
1426 if (kind == dlang_top_level)
1427 {
1428 if (mangled == NULL || *mangled != '\0')
1429 return NULL;
1430 }
1431 }
1432
43b1b9ed
IB
1433 return mangled;
1434}
1435
1436/* Demangle the tuple from MANGLED and append it to DECL.
1437 Return the remaining string on success or NULL on failure. */
1438static const char *
1439dlang_parse_tuple (string *decl, const char *mangled)
1440{
1441 char *endptr;
1442 long elements = strtol (mangled, &endptr, 10);
1443
1444 if (endptr == NULL || elements < 0)
1445 return NULL;
1446
1447 mangled = endptr;
1448 string_append (decl, "Tuple!(");
1449
1450 while (elements--)
1451 {
1452 mangled = dlang_type (decl, mangled);
1453 if (elements != 0)
1454 string_append (decl, ", ");
1455 }
1456
1457 string_append (decl, ")");
1458 return mangled;
1459}
1460
1461/* Demangle the argument list from MANGLED and append it to DECL.
1462 Return the remaining string on success or NULL on failure. */
1463static const char *
1464dlang_template_args (string *decl, const char *mangled)
1465{
1466 size_t n = 0;
1467
1468 while (mangled && *mangled != '\0')
1469 {
1470 switch (*mangled)
1471 {
1472 case 'Z': /* End of parameter list. */
1473 mangled++;
1474 return mangled;
1475 }
1476
1477 if (n++)
1478 string_append (decl, ", ");
1479
ed4cdb85
IB
1480 /* Skip over specialised template prefix. */
1481 if (*mangled == 'H')
1482 mangled++;
1483
43b1b9ed
IB
1484 switch (*mangled)
1485 {
1486 case 'S': /* Symbol parameter. */
1487 mangled++;
7e865541 1488 mangled = dlang_parse_symbol (decl, mangled, dlang_template_param);
43b1b9ed
IB
1489 break;
1490 case 'T': /* Type parameter. */
1491 mangled++;
1492 mangled = dlang_type (decl, mangled);
1493 break;
1494 case 'V': /* Value parameter. */
1495 {
1496 string name;
1497 char type;
1498
1499 /* Peek at the type. */
1500 mangled++;
1501 type = *mangled;
1502
1503 /* In the few instances where the type is actually desired in
1504 the output, it should precede the value from dlang_value. */
1505 string_init (&name);
1506 mangled = dlang_type (&name, mangled);
1507 string_need (&name, 1);
1508 *(name.p) = '\0';
1509
1510 mangled = dlang_value (decl, mangled, name.b, type);
1511 string_delete (&name);
1512 break;
1513 }
1514
1515 default:
1516 return NULL;
1517 }
1518 }
1519
1520 return mangled;
1521}
1522
1523/* Extract and demangle the template symbol in MANGLED, expected to
1524 be made up of LEN characters, and append it to DECL.
1525 Returns the remaining signature on success or NULL on failure. */
1526static const char *
1527dlang_parse_template (string *decl, const char *mangled, long len)
1528{
1529 const char *start = mangled;
1530
1531 /* Template instance names have the types and values of its parameters
1532 encoded into it.
1533
1534 TemplateInstanceName:
1535 Number __T LName TemplateArgs Z
1536 ^
1537 The start pointer should be at the above location, and LEN should be
1538 the value of the decoded number.
1539 */
1540 if (strncmp (mangled, "__T", 3) != 0)
1541 return NULL;
1542
1543 mangled += 3;
1544
1545 /* Template identifier. */
7e865541 1546 mangled = dlang_identifier (decl, mangled, dlang_template_ident);
43b1b9ed
IB
1547
1548 /* Template arguments. */
1549 string_append (decl, "!(");
1550 mangled = dlang_template_args (decl, mangled);
1551 string_append (decl, ")");
1552
1553 /* Check for template name length mismatch. */
1554 if (mangled && (mangled - start) != len)
1555 return NULL;
1556
1557 return mangled;
1558}
1559
1560/* Extract and demangle the symbol in MANGLED. Returns the demangled
1561 signature on success or NULL on failure. */
1562
1563char *
1564dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
1565{
1566 string decl;
1567 char *demangled = NULL;
1568
1569 if (mangled == NULL || *mangled == '\0')
1570 return NULL;
1571
1572 if (strncmp (mangled, "_D", 2) != 0)
1573 return NULL;
1574
1575 string_init (&decl);
1576
1577 if (strcmp (mangled, "_Dmain") == 0)
1578 {
1579 string_append (&decl, "D main");
1580 }
1581 else
1582 {
1583 mangled += 2;
1584
7e865541 1585 if (dlang_parse_symbol (&decl, mangled, dlang_top_level) == NULL)
43b1b9ed
IB
1586 string_delete (&decl);
1587 }
1588
1589 if (string_length (&decl) > 0)
1590 {
1591 string_need (&decl, 1);
1592 *(decl.p) = '\0';
1593 demangled = decl.b;
1594 }
1595
1596 return demangled;
1597}
1598