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