Commit | Line | Data |
---|---|---|
b55f9678 | 1 | /* Demangler for the D programming language |
533da483 | 2 | Copyright (C) 2014-2020 Free Software Foundation, Inc. |
b55f9678 IB |
3 | Written by Iain Buclaw (ibuclaw@gdcproject.org) |
4 | ||
5 | This file is part of the libiberty library. | |
6 | Libiberty is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Library General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2 of the License, or (at your option) any later version. | |
10 | ||
11 | In addition to the permissions in the GNU Library General Public | |
12 | License, the Free Software Foundation gives you unlimited permission | |
13 | to link the compiled version of this file into combinations with other | |
14 | programs, and to distribute those combinations without any restriction | |
15 | coming from the use of this file. (The Library Public License | |
16 | restrictions do apply in other respects; for example, they cover | |
17 | modification of the file, and distribution when not linked into a | |
18 | combined executable.) | |
19 | ||
20 | Libiberty is distributed in the hope that it will be useful, | |
21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
23 | Library General Public License for more details. | |
24 | ||
25 | You should have received a copy of the GNU Library General Public | |
26 | License along with libiberty; see the file COPYING.LIB. | |
27 | If not, see <http://www.gnu.org/licenses/>. */ | |
28 | ||
d7e2ebe7 | 29 | /* This file exports one function; dlang_demangle. */ |
b55f9678 IB |
30 | |
31 | #ifdef HAVE_CONFIG_H | |
32 | #include "config.h" | |
33 | #endif | |
7ade7fba AM |
34 | #ifdef HAVE_LIMITS_H |
35 | #include <limits.h> | |
36 | #endif | |
b55f9678 IB |
37 | |
38 | #include "safe-ctype.h" | |
39 | ||
40 | #include <sys/types.h> | |
41 | #include <string.h> | |
42 | #include <stdio.h> | |
43 | ||
44 | #ifdef HAVE_STDLIB_H | |
45 | #include <stdlib.h> | |
b55f9678 IB |
46 | #endif |
47 | ||
48 | #include <demangle.h> | |
49 | #include "libiberty.h" | |
50 | ||
7ade7fba AM |
51 | #ifndef ULONG_MAX |
52 | #define ULONG_MAX (~0UL) | |
53 | #endif | |
54 | #ifndef UINT_MAX | |
55 | #define UINT_MAX (~0U) | |
56 | #endif | |
57 | ||
b55f9678 IB |
58 | /* A mini string-handling package */ |
59 | ||
60 | typedef struct string /* Beware: these aren't required to be */ | |
61 | { /* '\0' terminated. */ | |
62 | char *b; /* pointer to start of string */ | |
63 | char *p; /* pointer after last character */ | |
64 | char *e; /* pointer after end of allocated space */ | |
65 | } string; | |
66 | ||
67 | static void | |
7ade7fba | 68 | string_need (string *s, size_t n) |
b55f9678 | 69 | { |
7ade7fba | 70 | size_t tem; |
b55f9678 IB |
71 | |
72 | if (s->b == NULL) | |
73 | { | |
74 | if (n < 32) | |
75 | { | |
76 | n = 32; | |
77 | } | |
78 | s->p = s->b = XNEWVEC (char, n); | |
79 | s->e = s->b + n; | |
80 | } | |
7ade7fba | 81 | else if ((size_t) (s->e - s->p) < n) |
b55f9678 IB |
82 | { |
83 | tem = s->p - s->b; | |
84 | n += tem; | |
85 | n *= 2; | |
86 | s->b = XRESIZEVEC (char, s->b, n); | |
87 | s->p = s->b + tem; | |
88 | s->e = s->b + n; | |
89 | } | |
90 | } | |
91 | ||
92 | static void | |
93 | string_delete (string *s) | |
94 | { | |
95 | if (s->b != NULL) | |
96 | { | |
97 | XDELETEVEC (s->b); | |
98 | s->b = s->e = s->p = NULL; | |
99 | } | |
100 | } | |
101 | ||
102 | static void | |
103 | string_init (string *s) | |
104 | { | |
105 | s->b = s->p = s->e = NULL; | |
106 | } | |
107 | ||
108 | static int | |
109 | string_length (string *s) | |
110 | { | |
111 | if (s->p == s->b) | |
112 | { | |
113 | return 0; | |
114 | } | |
115 | return s->p - s->b; | |
116 | } | |
117 | ||
118 | static void | |
119 | string_setlength (string *s, int n) | |
120 | { | |
121 | if (n - string_length (s) < 0) | |
122 | { | |
123 | s->p = s->b + n; | |
124 | } | |
125 | } | |
126 | ||
127 | static void | |
128 | string_append (string *p, const char *s) | |
129 | { | |
7ade7fba | 130 | size_t n = strlen (s); |
b55f9678 IB |
131 | string_need (p, n); |
132 | memcpy (p->p, s, n); | |
133 | p->p += n; | |
134 | } | |
135 | ||
136 | static void | |
7ade7fba | 137 | string_appendn (string *p, const char *s, size_t n) |
b55f9678 IB |
138 | { |
139 | if (n != 0) | |
140 | { | |
141 | string_need (p, n); | |
142 | memcpy (p->p, s, n); | |
143 | p->p += n; | |
144 | } | |
145 | } | |
146 | ||
147 | static void | |
7ade7fba | 148 | string_prependn (string *p, const char *s, size_t n) |
b55f9678 IB |
149 | { |
150 | char *q; | |
151 | ||
152 | if (n != 0) | |
153 | { | |
154 | string_need (p, n); | |
155 | for (q = p->p - 1; q >= p->b; q--) | |
156 | { | |
157 | q[n] = q[0]; | |
158 | } | |
159 | memcpy (p->b, s, n); | |
160 | p->p += n; | |
161 | } | |
162 | } | |
163 | ||
164 | static void | |
165 | string_prepend (string *p, const char *s) | |
166 | { | |
167 | if (s != NULL && *s != '\0') | |
168 | { | |
169 | string_prependn (p, s, strlen (s)); | |
170 | } | |
171 | } | |
172 | ||
727b7b18 L |
173 | /* Demangle information structure we pass around. */ |
174 | struct dlang_info | |
f91ca6bc | 175 | { |
727b7b18 L |
176 | /* The string we are demangling. */ |
177 | const char *s; | |
178 | /* The index of the last back reference. */ | |
179 | int last_backref; | |
f91ca6bc IB |
180 | }; |
181 | ||
727b7b18 | 182 | /* Pass as the LEN to dlang_parse_template if symbol length is not known. */ |
7ade7fba | 183 | #define TEMPLATE_LENGTH_UNKNOWN (-1UL) |
727b7b18 | 184 | |
b55f9678 | 185 | /* Prototypes for forward referenced functions */ |
727b7b18 L |
186 | static const char *dlang_function_type (string *, const char *, |
187 | struct dlang_info *); | |
b55f9678 | 188 | |
727b7b18 L |
189 | static const char *dlang_function_args (string *, const char *, |
190 | struct dlang_info *); | |
191 | ||
192 | static const char *dlang_type (string *, const char *, struct dlang_info *); | |
b55f9678 IB |
193 | |
194 | static const char *dlang_value (string *, const char *, const char *, char); | |
195 | ||
d7e2ebe7 | 196 | static const char *dlang_parse_qualified (string *, const char *, |
727b7b18 | 197 | struct dlang_info *, int); |
d7e2ebe7 IB |
198 | |
199 | static const char *dlang_parse_mangle (string *, const char *, | |
727b7b18 L |
200 | struct dlang_info *); |
201 | ||
202 | static const char *dlang_parse_tuple (string *, const char *, | |
203 | struct dlang_info *); | |
b55f9678 | 204 | |
727b7b18 | 205 | static const char *dlang_parse_template (string *, const char *, |
7ade7fba | 206 | struct dlang_info *, unsigned long); |
b55f9678 | 207 | |
7ade7fba | 208 | static const char *dlang_lname (string *, const char *, unsigned long); |
b55f9678 IB |
209 | |
210 | ||
d7e2ebe7 | 211 | /* Extract the number from MANGLED, and assign the result to RET. |
7ade7fba AM |
212 | Return the remaining string on success or NULL on failure. |
213 | A result larger than UINT_MAX is considered a failure. */ | |
d7e2ebe7 | 214 | static const char * |
7ade7fba | 215 | dlang_number (const char *mangled, unsigned long *ret) |
d7e2ebe7 IB |
216 | { |
217 | /* Return NULL if trying to extract something that isn't a digit. */ | |
218 | if (mangled == NULL || !ISDIGIT (*mangled)) | |
219 | return NULL; | |
220 | ||
7ade7fba | 221 | unsigned long val = 0; |
d7e2ebe7 IB |
222 | |
223 | while (ISDIGIT (*mangled)) | |
224 | { | |
7ade7fba | 225 | unsigned long digit = mangled[0] - '0'; |
d7e2ebe7 | 226 | |
7ade7fba AM |
227 | /* Check for overflow. */ |
228 | if (val > (UINT_MAX - digit) / 10) | |
d7e2ebe7 IB |
229 | return NULL; |
230 | ||
7ade7fba | 231 | val = val * 10 + digit; |
d7e2ebe7 IB |
232 | mangled++; |
233 | } | |
234 | ||
7ade7fba | 235 | if (*mangled == '\0') |
d7e2ebe7 IB |
236 | return NULL; |
237 | ||
7ade7fba | 238 | *ret = val; |
d7e2ebe7 IB |
239 | return mangled; |
240 | } | |
241 | ||
242 | /* Extract the hex-digit from MANGLED, and assign the result to RET. | |
243 | Return the remaining string on success or NULL on failure. */ | |
244 | static const char * | |
245 | dlang_hexdigit (const char *mangled, char *ret) | |
246 | { | |
247 | char c; | |
248 | ||
249 | /* Return NULL if trying to extract something that isn't a hexdigit. */ | |
250 | if (mangled == NULL || !ISXDIGIT (mangled[0]) || !ISXDIGIT (mangled[1])) | |
251 | return NULL; | |
252 | ||
253 | c = mangled[0]; | |
254 | if (!ISDIGIT (c)) | |
255 | (*ret) = (c - (ISUPPER (c) ? 'A' : 'a') + 10); | |
256 | else | |
257 | (*ret) = (c - '0'); | |
258 | ||
259 | c = mangled[1]; | |
260 | if (!ISDIGIT (c)) | |
261 | (*ret) = (*ret << 4) | (c - (ISUPPER (c) ? 'A' : 'a') + 10); | |
262 | else | |
263 | (*ret) = (*ret << 4) | (c - '0'); | |
264 | ||
265 | mangled += 2; | |
266 | ||
267 | return mangled; | |
268 | } | |
269 | ||
270 | /* Extract the function calling convention from MANGLED and | |
271 | return 1 on success or 0 on failure. */ | |
272 | static int | |
273 | dlang_call_convention_p (const char *mangled) | |
274 | { | |
275 | switch (*mangled) | |
276 | { | |
277 | case 'F': case 'U': case 'V': | |
278 | case 'W': case 'R': case 'Y': | |
279 | return 1; | |
280 | ||
281 | default: | |
282 | return 0; | |
283 | } | |
284 | } | |
285 | ||
727b7b18 | 286 | /* Extract the back reference position from MANGLED, and assign the result |
7ade7fba AM |
287 | to RET. Return the remaining string on success or NULL on failure. |
288 | A result <= 0 is a failure. */ | |
727b7b18 L |
289 | static const char * |
290 | dlang_decode_backref (const char *mangled, long *ret) | |
291 | { | |
292 | /* Return NULL if trying to extract something that isn't a digit. */ | |
293 | if (mangled == NULL || !ISALPHA (*mangled)) | |
294 | return NULL; | |
295 | ||
296 | /* Any identifier or non-basic type that has been emitted to the mangled | |
297 | symbol before will not be emitted again, but is referenced by a special | |
298 | sequence encoding the relative position of the original occurrence in the | |
299 | mangled symbol name. | |
300 | ||
301 | Numbers in back references are encoded with base 26 by upper case letters | |
302 | A-Z for higher digits but lower case letters a-z for the last digit. | |
303 | ||
304 | NumberBackRef: | |
305 | [a-z] | |
306 | [A-Z] NumberBackRef | |
307 | ^ | |
308 | */ | |
7ade7fba | 309 | unsigned long val = 0; |
727b7b18 L |
310 | |
311 | while (ISALPHA (*mangled)) | |
312 | { | |
7ade7fba AM |
313 | /* Check for overflow. */ |
314 | if (val > (ULONG_MAX - 25) / 26) | |
315 | break; | |
727b7b18 | 316 | |
7ade7fba | 317 | val *= 26; |
727b7b18 L |
318 | |
319 | if (mangled[0] >= 'a' && mangled[0] <= 'z') | |
320 | { | |
7ade7fba AM |
321 | val += mangled[0] - 'a'; |
322 | if ((long) val <= 0) | |
323 | break; | |
324 | *ret = val; | |
727b7b18 L |
325 | return mangled + 1; |
326 | } | |
327 | ||
7ade7fba | 328 | val += mangled[0] - 'A'; |
727b7b18 L |
329 | mangled++; |
330 | } | |
331 | ||
332 | return NULL; | |
333 | } | |
334 | ||
335 | /* Extract the symbol pointed at by the back reference and assign the result | |
336 | to RET. Return the remaining string on success or NULL on failure. */ | |
337 | static const char * | |
338 | dlang_backref (const char *mangled, const char **ret, struct dlang_info *info) | |
339 | { | |
340 | (*ret) = NULL; | |
341 | ||
342 | if (mangled == NULL || *mangled != 'Q') | |
343 | return NULL; | |
344 | ||
345 | /* Position of 'Q'. */ | |
346 | const char *qpos = mangled; | |
347 | long refpos; | |
348 | mangled++; | |
349 | ||
350 | mangled = dlang_decode_backref (mangled, &refpos); | |
351 | if (mangled == NULL) | |
352 | return NULL; | |
353 | ||
7ade7fba | 354 | if (refpos > qpos - info->s) |
727b7b18 L |
355 | return NULL; |
356 | ||
357 | /* Set the position of the back reference. */ | |
358 | (*ret) = qpos - refpos; | |
359 | ||
360 | return mangled; | |
361 | } | |
362 | ||
363 | /* Demangle a back referenced symbol from MANGLED and append it to DECL. | |
364 | Return the remaining string on success or NULL on failure. */ | |
365 | static const char * | |
366 | dlang_symbol_backref (string *decl, const char *mangled, | |
367 | struct dlang_info *info) | |
368 | { | |
369 | /* An identifier back reference always points to a digit 0 to 9. | |
370 | ||
371 | IdentifierBackRef: | |
372 | Q NumberBackRef | |
373 | ^ | |
374 | */ | |
375 | const char *backref; | |
7ade7fba | 376 | unsigned long len; |
727b7b18 L |
377 | |
378 | /* Get position of the back reference. */ | |
379 | mangled = dlang_backref (mangled, &backref, info); | |
380 | ||
381 | /* Must point to a simple identifier. */ | |
382 | backref = dlang_number (backref, &len); | |
383 | if (backref == NULL) | |
384 | return NULL; | |
385 | ||
386 | backref = dlang_lname (decl, backref, len); | |
387 | if (backref == NULL) | |
388 | return NULL; | |
389 | ||
390 | return mangled; | |
391 | } | |
392 | ||
393 | /* Demangle a back referenced type from MANGLED and append it to DECL. | |
394 | IS_FUNCTION is 1 if the back referenced type is expected to be a function. | |
395 | Return the remaining string on success or NULL on failure. */ | |
396 | static const char * | |
397 | dlang_type_backref (string *decl, const char *mangled, struct dlang_info *info, | |
398 | int is_function) | |
399 | { | |
400 | /* A type back reference always points to a letter. | |
401 | ||
402 | TypeBackRef: | |
403 | Q NumberBackRef | |
404 | ^ | |
405 | */ | |
406 | const char *backref; | |
407 | ||
408 | /* If we appear to be moving backwards through the mangle string, then | |
409 | bail as this may be a recursive back reference. */ | |
410 | if (mangled - info->s >= info->last_backref) | |
411 | return NULL; | |
412 | ||
413 | int save_refpos = info->last_backref; | |
414 | info->last_backref = mangled - info->s; | |
415 | ||
416 | /* Get position of the back reference. */ | |
417 | mangled = dlang_backref (mangled, &backref, info); | |
418 | ||
419 | /* Must point to a type. */ | |
420 | if (is_function) | |
421 | backref = dlang_function_type (decl, backref, info); | |
422 | else | |
423 | backref = dlang_type (decl, backref, info); | |
424 | ||
425 | info->last_backref = save_refpos; | |
426 | ||
427 | if (backref == NULL) | |
428 | return NULL; | |
429 | ||
430 | return mangled; | |
431 | } | |
432 | ||
433 | /* Extract the beginning of a symbol name from MANGLED and | |
434 | return 1 on success or 0 on failure. */ | |
435 | static int | |
436 | dlang_symbol_name_p (const char *mangled, struct dlang_info *info) | |
437 | { | |
438 | long ret; | |
439 | const char *qref = mangled; | |
440 | ||
441 | if (ISDIGIT (*mangled)) | |
442 | return 1; | |
443 | ||
444 | if (mangled[0] == '_' && mangled[1] == '_' | |
445 | && (mangled[2] == 'T' || mangled[2] == 'U')) | |
446 | return 1; | |
447 | ||
448 | if (*mangled != 'Q') | |
449 | return 0; | |
450 | ||
451 | mangled = dlang_decode_backref (mangled + 1, &ret); | |
7ade7fba | 452 | if (mangled == NULL || ret > qref - info->s) |
727b7b18 L |
453 | return 0; |
454 | ||
455 | return ISDIGIT (qref[-ret]); | |
456 | } | |
457 | ||
b55f9678 IB |
458 | /* Demangle the calling convention from MANGLED and append it to DECL. |
459 | Return the remaining string on success or NULL on failure. */ | |
460 | static const char * | |
461 | dlang_call_convention (string *decl, const char *mangled) | |
462 | { | |
463 | if (mangled == NULL || *mangled == '\0') | |
f91ca6bc | 464 | return NULL; |
b55f9678 IB |
465 | |
466 | switch (*mangled) | |
467 | { | |
468 | case 'F': /* (D) */ | |
469 | mangled++; | |
470 | break; | |
471 | case 'U': /* (C) */ | |
472 | mangled++; | |
473 | string_append (decl, "extern(C) "); | |
474 | break; | |
475 | case 'W': /* (Windows) */ | |
476 | mangled++; | |
477 | string_append (decl, "extern(Windows) "); | |
478 | break; | |
479 | case 'V': /* (Pascal) */ | |
480 | mangled++; | |
481 | string_append (decl, "extern(Pascal) "); | |
482 | break; | |
483 | case 'R': /* (C++) */ | |
484 | mangled++; | |
485 | string_append (decl, "extern(C++) "); | |
486 | break; | |
9d98de83 IB |
487 | case 'Y': /* (Objective-C) */ |
488 | mangled++; | |
489 | string_append (decl, "extern(Objective-C) "); | |
490 | break; | |
b55f9678 IB |
491 | default: |
492 | return NULL; | |
493 | } | |
494 | ||
495 | return mangled; | |
496 | } | |
497 | ||
f91ca6bc IB |
498 | /* Extract the type modifiers from MANGLED and append them to DECL. |
499 | Returns the remaining signature on success or NULL on failure. */ | |
500 | static const char * | |
501 | dlang_type_modifiers (string *decl, const char *mangled) | |
502 | { | |
503 | if (mangled == NULL || *mangled == '\0') | |
504 | return NULL; | |
505 | ||
506 | switch (*mangled) | |
507 | { | |
508 | case 'x': /* const */ | |
509 | mangled++; | |
510 | string_append (decl, " const"); | |
511 | return mangled; | |
512 | case 'y': /* immutable */ | |
513 | mangled++; | |
514 | string_append (decl, " immutable"); | |
515 | return mangled; | |
516 | case 'O': /* shared */ | |
517 | mangled++; | |
518 | string_append (decl, " shared"); | |
519 | return dlang_type_modifiers (decl, mangled); | |
520 | case 'N': | |
521 | mangled++; | |
522 | if (*mangled == 'g') /* wild */ | |
523 | { | |
524 | mangled++; | |
525 | string_append (decl, " inout"); | |
526 | return dlang_type_modifiers (decl, mangled); | |
527 | } | |
528 | else | |
529 | return NULL; | |
530 | ||
531 | default: | |
532 | return mangled; | |
533 | } | |
534 | } | |
535 | ||
b55f9678 IB |
536 | /* Demangle the D function attributes from MANGLED and append it to DECL. |
537 | Return the remaining string on success or NULL on failure. */ | |
538 | static const char * | |
539 | dlang_attributes (string *decl, const char *mangled) | |
540 | { | |
541 | if (mangled == NULL || *mangled == '\0') | |
f91ca6bc | 542 | return NULL; |
b55f9678 IB |
543 | |
544 | while (*mangled == 'N') | |
545 | { | |
546 | mangled++; | |
547 | switch (*mangled) | |
548 | { | |
549 | case 'a': /* pure */ | |
550 | mangled++; | |
551 | string_append (decl, "pure "); | |
552 | continue; | |
553 | case 'b': /* nothrow */ | |
554 | mangled++; | |
555 | string_append (decl, "nothrow "); | |
556 | continue; | |
557 | case 'c': /* ref */ | |
558 | mangled++; | |
559 | string_append (decl, "ref "); | |
560 | continue; | |
561 | case 'd': /* @property */ | |
562 | mangled++; | |
563 | string_append (decl, "@property "); | |
564 | continue; | |
565 | case 'e': /* @trusted */ | |
566 | mangled++; | |
567 | string_append (decl, "@trusted "); | |
568 | continue; | |
569 | case 'f': /* @safe */ | |
570 | mangled++; | |
571 | string_append (decl, "@safe "); | |
572 | continue; | |
573 | case 'g': | |
574 | case 'h': | |
f91ca6bc | 575 | case 'k': |
b55f9678 IB |
576 | /* inout parameter is represented as 'Ng'. |
577 | vector parameter is represented as 'Nh'. | |
f91ca6bc | 578 | return paramenter is represented as 'Nk'. |
b55f9678 IB |
579 | If we see this, then we know we're really in the |
580 | parameter list. Rewind and break. */ | |
581 | mangled--; | |
582 | break; | |
583 | case 'i': /* @nogc */ | |
584 | mangled++; | |
585 | string_append (decl, "@nogc "); | |
586 | continue; | |
f91ca6bc IB |
587 | case 'j': /* return */ |
588 | mangled++; | |
589 | string_append (decl, "return "); | |
590 | continue; | |
d7e2ebe7 IB |
591 | case 'l': /* scope */ |
592 | mangled++; | |
593 | string_append (decl, "scope "); | |
594 | continue; | |
727b7b18 L |
595 | case 'm': /* @live */ |
596 | mangled++; | |
597 | string_append (decl, "@live "); | |
598 | continue; | |
f91ca6bc IB |
599 | |
600 | default: /* unknown attribute */ | |
601 | return NULL; | |
b55f9678 IB |
602 | } |
603 | break; | |
604 | } | |
605 | ||
606 | return mangled; | |
607 | } | |
608 | ||
727b7b18 L |
609 | /* Demangle the function type from MANGLED without the return type. |
610 | The arguments are appended to ARGS, the calling convention is appended | |
611 | to CALL and attributes are appended to ATTR. Any of these can be NULL | |
612 | to throw the information away. Return the remaining string on success | |
613 | or NULL on failure. */ | |
614 | static const char * | |
615 | dlang_function_type_noreturn (string *args, string *call, string *attr, | |
616 | const char *mangled, struct dlang_info *info) | |
617 | { | |
618 | string dump; | |
619 | string_init (&dump); | |
620 | ||
621 | /* Skip over calling convention and attributes. */ | |
622 | mangled = dlang_call_convention (call ? call : &dump, mangled); | |
623 | mangled = dlang_attributes (attr ? attr : &dump, mangled); | |
624 | ||
625 | if (args) | |
626 | string_append (args, "("); | |
627 | ||
628 | mangled = dlang_function_args (args ? args : &dump, mangled, info); | |
629 | if (args) | |
630 | string_append (args, ")"); | |
631 | ||
632 | string_delete (&dump); | |
633 | return mangled; | |
634 | } | |
635 | ||
b55f9678 IB |
636 | /* Demangle the function type from MANGLED and append it to DECL. |
637 | Return the remaining string on success or NULL on failure. */ | |
638 | static const char * | |
727b7b18 | 639 | dlang_function_type (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 IB |
640 | { |
641 | string attr, args, type; | |
b55f9678 IB |
642 | |
643 | if (mangled == NULL || *mangled == '\0') | |
f91ca6bc | 644 | return NULL; |
b55f9678 IB |
645 | |
646 | /* The order of the mangled string is: | |
647 | CallConvention FuncAttrs Arguments ArgClose Type | |
648 | ||
649 | The demangled string is re-ordered as: | |
650 | CallConvention Type Arguments FuncAttrs | |
651 | */ | |
652 | string_init (&attr); | |
653 | string_init (&args); | |
654 | string_init (&type); | |
655 | ||
727b7b18 | 656 | mangled = dlang_function_type_noreturn (&args, decl, &attr, mangled, info); |
b55f9678 IB |
657 | |
658 | /* Function return type. */ | |
727b7b18 | 659 | mangled = dlang_type (&type, mangled, info); |
b55f9678 IB |
660 | |
661 | /* Append to decl in order. */ | |
727b7b18 L |
662 | string_appendn (decl, type.b, string_length (&type)); |
663 | string_appendn (decl, args.b, string_length (&args)); | |
664 | string_append (decl, " "); | |
665 | string_appendn (decl, attr.b, string_length (&attr)); | |
b55f9678 IB |
666 | |
667 | string_delete (&attr); | |
668 | string_delete (&args); | |
669 | string_delete (&type); | |
670 | return mangled; | |
671 | } | |
672 | ||
673 | /* Demangle the argument list from MANGLED and append it to DECL. | |
674 | Return the remaining string on success or NULL on failure. */ | |
675 | static const char * | |
727b7b18 | 676 | dlang_function_args (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 IB |
677 | { |
678 | size_t n = 0; | |
679 | ||
680 | while (mangled && *mangled != '\0') | |
681 | { | |
682 | switch (*mangled) | |
683 | { | |
684 | case 'X': /* (variadic T t...) style. */ | |
685 | mangled++; | |
686 | string_append (decl, "..."); | |
687 | return mangled; | |
688 | case 'Y': /* (variadic T t, ...) style. */ | |
689 | mangled++; | |
9d98de83 IB |
690 | if (n != 0) |
691 | string_append (decl, ", "); | |
692 | string_append (decl, "..."); | |
b55f9678 IB |
693 | return mangled; |
694 | case 'Z': /* Normal function. */ | |
695 | mangled++; | |
696 | return mangled; | |
697 | } | |
698 | ||
699 | if (n++) | |
700 | string_append (decl, ", "); | |
701 | ||
702 | if (*mangled == 'M') /* scope(T) */ | |
703 | { | |
704 | mangled++; | |
705 | string_append (decl, "scope "); | |
706 | } | |
707 | ||
f91ca6bc IB |
708 | if (mangled[0] == 'N' && mangled[1] == 'k') /* return(T) */ |
709 | { | |
710 | mangled += 2; | |
711 | string_append (decl, "return "); | |
712 | } | |
713 | ||
b55f9678 IB |
714 | switch (*mangled) |
715 | { | |
7ade7fba AM |
716 | case 'I': /* in(T) */ |
717 | mangled++; | |
718 | string_append (decl, "in "); | |
719 | if (*mangled == 'K') /* in ref(T) */ | |
720 | { | |
721 | mangled++; | |
722 | string_append (decl, "ref "); | |
723 | } | |
724 | break; | |
b55f9678 IB |
725 | case 'J': /* out(T) */ |
726 | mangled++; | |
727 | string_append (decl, "out "); | |
728 | break; | |
729 | case 'K': /* ref(T) */ | |
730 | mangled++; | |
731 | string_append (decl, "ref "); | |
732 | break; | |
733 | case 'L': /* lazy(T) */ | |
734 | mangled++; | |
735 | string_append (decl, "lazy "); | |
736 | break; | |
737 | } | |
727b7b18 | 738 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
739 | } |
740 | ||
741 | return mangled; | |
742 | } | |
743 | ||
744 | /* Demangle the type from MANGLED and append it to DECL. | |
745 | Return the remaining string on success or NULL on failure. */ | |
746 | static const char * | |
727b7b18 | 747 | dlang_type (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 IB |
748 | { |
749 | if (mangled == NULL || *mangled == '\0') | |
f91ca6bc | 750 | return NULL; |
b55f9678 IB |
751 | |
752 | switch (*mangled) | |
753 | { | |
754 | case 'O': /* shared(T) */ | |
755 | mangled++; | |
756 | string_append (decl, "shared("); | |
727b7b18 | 757 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
758 | string_append (decl, ")"); |
759 | return mangled; | |
760 | case 'x': /* const(T) */ | |
761 | mangled++; | |
762 | string_append (decl, "const("); | |
727b7b18 | 763 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
764 | string_append (decl, ")"); |
765 | return mangled; | |
766 | case 'y': /* immutable(T) */ | |
767 | mangled++; | |
768 | string_append (decl, "immutable("); | |
727b7b18 | 769 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
770 | string_append (decl, ")"); |
771 | return mangled; | |
772 | case 'N': | |
773 | mangled++; | |
774 | if (*mangled == 'g') /* wild(T) */ | |
775 | { | |
776 | mangled++; | |
777 | string_append (decl, "inout("); | |
727b7b18 | 778 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
779 | string_append (decl, ")"); |
780 | return mangled; | |
781 | } | |
782 | else if (*mangled == 'h') /* vector(T) */ | |
783 | { | |
784 | mangled++; | |
785 | string_append (decl, "__vector("); | |
727b7b18 | 786 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
787 | string_append (decl, ")"); |
788 | return mangled; | |
789 | } | |
790 | else | |
791 | return NULL; | |
792 | case 'A': /* dynamic array (T[]) */ | |
793 | mangled++; | |
727b7b18 | 794 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
795 | string_append (decl, "[]"); |
796 | return mangled; | |
797 | case 'G': /* static array (T[N]) */ | |
798 | { | |
799 | const char *numptr; | |
800 | size_t num = 0; | |
801 | mangled++; | |
802 | ||
803 | numptr = mangled; | |
804 | while (ISDIGIT (*mangled)) | |
805 | { | |
806 | num++; | |
807 | mangled++; | |
808 | } | |
727b7b18 | 809 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
810 | string_append (decl, "["); |
811 | string_appendn (decl, numptr, num); | |
812 | string_append (decl, "]"); | |
813 | return mangled; | |
814 | } | |
815 | case 'H': /* associative array (T[T]) */ | |
816 | { | |
817 | string type; | |
818 | size_t sztype; | |
819 | mangled++; | |
820 | ||
821 | string_init (&type); | |
727b7b18 | 822 | mangled = dlang_type (&type, mangled, info); |
b55f9678 IB |
823 | sztype = string_length (&type); |
824 | ||
727b7b18 | 825 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
826 | string_append (decl, "["); |
827 | string_appendn (decl, type.b, sztype); | |
828 | string_append (decl, "]"); | |
829 | ||
830 | string_delete (&type); | |
831 | return mangled; | |
832 | } | |
833 | case 'P': /* pointer (T*) */ | |
834 | mangled++; | |
d7e2ebe7 | 835 | if (!dlang_call_convention_p (mangled)) |
9d98de83 | 836 | { |
727b7b18 | 837 | mangled = dlang_type (decl, mangled, info); |
d7e2ebe7 | 838 | string_append (decl, "*"); |
9d98de83 IB |
839 | return mangled; |
840 | } | |
d7e2ebe7 IB |
841 | /* Fall through */ |
842 | case 'F': /* function T (D) */ | |
843 | case 'U': /* function T (C) */ | |
844 | case 'W': /* function T (Windows) */ | |
845 | case 'V': /* function T (Pascal) */ | |
846 | case 'R': /* function T (C++) */ | |
847 | case 'Y': /* function T (Objective-C) */ | |
848 | /* Function pointer types don't include the trailing asterisk. */ | |
727b7b18 | 849 | mangled = dlang_function_type (decl, mangled, info); |
d7e2ebe7 | 850 | string_append (decl, "function"); |
b55f9678 | 851 | return mangled; |
b55f9678 IB |
852 | case 'C': /* class T */ |
853 | case 'S': /* struct T */ | |
854 | case 'E': /* enum T */ | |
855 | case 'T': /* typedef T */ | |
856 | mangled++; | |
727b7b18 | 857 | return dlang_parse_qualified (decl, mangled, info, 0); |
b55f9678 | 858 | case 'D': /* delegate T */ |
f91ca6bc IB |
859 | { |
860 | string mods; | |
861 | size_t szmods; | |
b55f9678 | 862 | mangled++; |
f91ca6bc IB |
863 | |
864 | string_init (&mods); | |
865 | mangled = dlang_type_modifiers (&mods, mangled); | |
866 | szmods = string_length (&mods); | |
867 | ||
727b7b18 L |
868 | /* Back referenced function type. */ |
869 | if (*mangled == 'Q') | |
870 | mangled = dlang_type_backref (decl, mangled, info, 1); | |
871 | else | |
872 | mangled = dlang_function_type (decl, mangled, info); | |
873 | ||
b55f9678 | 874 | string_append (decl, "delegate"); |
f91ca6bc IB |
875 | string_appendn (decl, mods.b, szmods); |
876 | ||
877 | string_delete (&mods); | |
b55f9678 | 878 | return mangled; |
f91ca6bc | 879 | } |
b55f9678 IB |
880 | case 'B': /* tuple T */ |
881 | mangled++; | |
727b7b18 | 882 | return dlang_parse_tuple (decl, mangled, info); |
b55f9678 | 883 | |
b55f9678 IB |
884 | /* Basic types */ |
885 | case 'n': | |
886 | mangled++; | |
887 | string_append (decl, "none"); | |
888 | return mangled; | |
889 | case 'v': | |
890 | mangled++; | |
891 | string_append (decl, "void"); | |
892 | return mangled; | |
893 | case 'g': | |
894 | mangled++; | |
895 | string_append (decl, "byte"); | |
896 | return mangled; | |
897 | case 'h': | |
898 | mangled++; | |
899 | string_append (decl, "ubyte"); | |
900 | return mangled; | |
901 | case 's': | |
902 | mangled++; | |
903 | string_append (decl, "short"); | |
904 | return mangled; | |
905 | case 't': | |
906 | mangled++; | |
907 | string_append (decl, "ushort"); | |
908 | return mangled; | |
909 | case 'i': | |
910 | mangled++; | |
911 | string_append (decl, "int"); | |
912 | return mangled; | |
913 | case 'k': | |
914 | mangled++; | |
915 | string_append (decl, "uint"); | |
916 | return mangled; | |
917 | case 'l': | |
918 | mangled++; | |
919 | string_append (decl, "long"); | |
920 | return mangled; | |
921 | case 'm': | |
922 | mangled++; | |
923 | string_append (decl, "ulong"); | |
924 | return mangled; | |
925 | case 'f': | |
926 | mangled++; | |
927 | string_append (decl, "float"); | |
928 | return mangled; | |
929 | case 'd': | |
930 | mangled++; | |
931 | string_append (decl, "double"); | |
932 | return mangled; | |
933 | case 'e': | |
934 | mangled++; | |
935 | string_append (decl, "real"); | |
936 | return mangled; | |
937 | ||
938 | /* Imaginary and Complex types */ | |
939 | case 'o': | |
940 | mangled++; | |
941 | string_append (decl, "ifloat"); | |
942 | return mangled; | |
943 | case 'p': | |
944 | mangled++; | |
945 | string_append (decl, "idouble"); | |
946 | return mangled; | |
947 | case 'j': | |
948 | mangled++; | |
949 | string_append (decl, "ireal"); | |
950 | return mangled; | |
951 | case 'q': | |
952 | mangled++; | |
953 | string_append (decl, "cfloat"); | |
954 | return mangled; | |
955 | case 'r': | |
956 | mangled++; | |
957 | string_append (decl, "cdouble"); | |
958 | return mangled; | |
959 | case 'c': | |
960 | mangled++; | |
961 | string_append (decl, "creal"); | |
962 | return mangled; | |
963 | ||
964 | /* Other types */ | |
965 | case 'b': | |
966 | mangled++; | |
967 | string_append (decl, "bool"); | |
968 | return mangled; | |
969 | case 'a': | |
970 | mangled++; | |
971 | string_append (decl, "char"); | |
972 | return mangled; | |
973 | case 'u': | |
974 | mangled++; | |
975 | string_append (decl, "wchar"); | |
976 | return mangled; | |
977 | case 'w': | |
978 | mangled++; | |
979 | string_append (decl, "dchar"); | |
980 | return mangled; | |
f91ca6bc IB |
981 | case 'z': |
982 | mangled++; | |
983 | switch (*mangled) | |
984 | { | |
985 | case 'i': | |
986 | mangled++; | |
987 | string_append (decl, "cent"); | |
988 | return mangled; | |
989 | case 'k': | |
990 | mangled++; | |
991 | string_append (decl, "ucent"); | |
992 | return mangled; | |
993 | } | |
994 | return NULL; | |
b55f9678 | 995 | |
727b7b18 L |
996 | /* Back referenced type. */ |
997 | case 'Q': | |
998 | return dlang_type_backref (decl, mangled, info, 0); | |
999 | ||
b55f9678 IB |
1000 | default: /* unhandled */ |
1001 | return NULL; | |
1002 | } | |
1003 | } | |
1004 | ||
1005 | /* Extract the identifier from MANGLED and append it to DECL. | |
1006 | Return the remaining string on success or NULL on failure. */ | |
1007 | static const char * | |
727b7b18 | 1008 | dlang_identifier (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 | 1009 | { |
7ade7fba | 1010 | unsigned long len; |
f91ca6bc | 1011 | |
727b7b18 | 1012 | if (mangled == NULL || *mangled == '\0') |
f91ca6bc IB |
1013 | return NULL; |
1014 | ||
727b7b18 L |
1015 | if (*mangled == 'Q') |
1016 | return dlang_symbol_backref (decl, mangled, info); | |
f91ca6bc | 1017 | |
727b7b18 L |
1018 | /* May be a template instance without a length prefix. */ |
1019 | if (mangled[0] == '_' && mangled[1] == '_' | |
1020 | && (mangled[2] == 'T' || mangled[2] == 'U')) | |
1021 | return dlang_parse_template (decl, mangled, info, TEMPLATE_LENGTH_UNKNOWN); | |
f91ca6bc | 1022 | |
727b7b18 | 1023 | const char *endptr = dlang_number (mangled, &len); |
f91ca6bc | 1024 | |
727b7b18 L |
1025 | if (endptr == NULL || len == 0) |
1026 | return NULL; | |
f91ca6bc | 1027 | |
7ade7fba | 1028 | if (strlen (endptr) < len) |
727b7b18 | 1029 | return NULL; |
f91ca6bc | 1030 | |
727b7b18 | 1031 | mangled = endptr; |
b55f9678 | 1032 | |
727b7b18 L |
1033 | /* May be a template instance with a length prefix. */ |
1034 | if (len >= 5 && mangled[0] == '_' && mangled[1] == '_' | |
1035 | && (mangled[2] == 'T' || mangled[2] == 'U')) | |
1036 | return dlang_parse_template (decl, mangled, info, len); | |
b55f9678 | 1037 | |
727b7b18 L |
1038 | return dlang_lname (decl, mangled, len); |
1039 | } | |
b55f9678 | 1040 | |
727b7b18 L |
1041 | /* Extract the plain identifier from MANGLED and prepend/append it to DECL |
1042 | with special treatment for some magic compiler generted symbols. | |
1043 | Return the remaining string on success or NULL on failure. */ | |
1044 | static const char * | |
7ade7fba | 1045 | dlang_lname (string *decl, const char *mangled, unsigned long len) |
727b7b18 L |
1046 | { |
1047 | switch (len) | |
1048 | { | |
1049 | case 6: | |
1050 | if (strncmp (mangled, "__ctor", len) == 0) | |
b55f9678 | 1051 | { |
727b7b18 L |
1052 | /* Constructor symbol for a class/struct. */ |
1053 | string_append (decl, "this"); | |
1054 | mangled += len; | |
1055 | return mangled; | |
1056 | } | |
1057 | else if (strncmp (mangled, "__dtor", len) == 0) | |
1058 | { | |
1059 | /* Destructor symbol for a class/struct. */ | |
1060 | string_append (decl, "~this"); | |
1061 | mangled += len; | |
1062 | return mangled; | |
1063 | } | |
1064 | else if (strncmp (mangled, "__initZ", len + 1) == 0) | |
1065 | { | |
1066 | /* The static initialiser for a given symbol. */ | |
1067 | string_prepend (decl, "initializer for "); | |
1068 | string_setlength (decl, string_length (decl) - 1); | |
1069 | mangled += len; | |
1070 | return mangled; | |
1071 | } | |
1072 | else if (strncmp (mangled, "__vtblZ", len + 1) == 0) | |
1073 | { | |
1074 | /* The vtable symbol for a given class. */ | |
1075 | string_prepend (decl, "vtable for "); | |
1076 | string_setlength (decl, string_length (decl) - 1); | |
1077 | mangled += len; | |
1078 | return mangled; | |
1079 | } | |
1080 | break; | |
f91ca6bc | 1081 | |
727b7b18 L |
1082 | case 7: |
1083 | if (strncmp (mangled, "__ClassZ", len + 1) == 0) | |
1084 | { | |
1085 | /* The classinfo symbol for a given class. */ | |
1086 | string_prepend (decl, "ClassInfo for "); | |
1087 | string_setlength (decl, string_length (decl) - 1); | |
1088 | mangled += len; | |
1089 | return mangled; | |
1090 | } | |
1091 | break; | |
f91ca6bc | 1092 | |
727b7b18 L |
1093 | case 10: |
1094 | if (strncmp (mangled, "__postblitMFZ", len + 3) == 0) | |
1095 | { | |
1096 | /* Postblit symbol for a struct. */ | |
1097 | string_append (decl, "this(this)"); | |
1098 | mangled += len + 3; | |
1099 | return mangled; | |
1100 | } | |
1101 | break; | |
f91ca6bc | 1102 | |
727b7b18 L |
1103 | case 11: |
1104 | if (strncmp (mangled, "__InterfaceZ", len + 1) == 0) | |
1105 | { | |
1106 | /* The interface symbol for a given class. */ | |
1107 | string_prepend (decl, "Interface for "); | |
1108 | string_setlength (decl, string_length (decl) - 1); | |
1109 | mangled += len; | |
1110 | return mangled; | |
b55f9678 | 1111 | } |
727b7b18 | 1112 | break; |
b55f9678 | 1113 | |
727b7b18 L |
1114 | case 12: |
1115 | if (strncmp (mangled, "__ModuleInfoZ", len + 1) == 0) | |
1116 | { | |
1117 | /* The ModuleInfo symbol for a given module. */ | |
1118 | string_prepend (decl, "ModuleInfo for "); | |
1119 | string_setlength (decl, string_length (decl) - 1); | |
1120 | mangled += len; | |
1121 | return mangled; | |
1122 | } | |
1123 | break; | |
b55f9678 | 1124 | } |
b55f9678 | 1125 | |
727b7b18 L |
1126 | string_appendn (decl, mangled, len); |
1127 | mangled += len; | |
1128 | ||
b55f9678 IB |
1129 | return mangled; |
1130 | } | |
1131 | ||
1132 | /* Extract the integer value from MANGLED and append it to DECL, | |
1133 | where TYPE is the type it should be represented as. | |
1134 | Return the remaining string on success or NULL on failure. */ | |
1135 | static const char * | |
1136 | dlang_parse_integer (string *decl, const char *mangled, char type) | |
1137 | { | |
1138 | if (type == 'a' || type == 'u' || type == 'w') | |
1139 | { | |
1140 | /* Parse character value. */ | |
f211b8c0 NC |
1141 | char value[20]; |
1142 | int pos = sizeof(value); | |
b55f9678 | 1143 | int width = 0; |
7ade7fba | 1144 | unsigned long val; |
b55f9678 | 1145 | |
d7e2ebe7 IB |
1146 | mangled = dlang_number (mangled, &val); |
1147 | if (mangled == NULL) | |
b55f9678 IB |
1148 | return NULL; |
1149 | ||
1150 | string_append (decl, "'"); | |
1151 | ||
1152 | if (type == 'a' && val >= 0x20 && val < 0x7F) | |
1153 | { | |
1154 | /* Represent as a character literal. */ | |
1155 | char c = (char) val; | |
1156 | string_appendn (decl, &c, 1); | |
1157 | } | |
1158 | else | |
1159 | { | |
1160 | /* Represent as a hexadecimal value. */ | |
1161 | switch (type) | |
1162 | { | |
1163 | case 'a': /* char */ | |
1164 | string_append (decl, "\\x"); | |
1165 | width = 2; | |
1166 | break; | |
1167 | case 'u': /* wchar */ | |
1168 | string_append (decl, "\\u"); | |
1169 | width = 4; | |
1170 | break; | |
1171 | case 'w': /* dchar */ | |
1172 | string_append (decl, "\\U"); | |
1173 | width = 8; | |
1174 | break; | |
1175 | } | |
1176 | ||
1177 | while (val > 0) | |
1178 | { | |
1179 | int digit = val % 16; | |
1180 | ||
1181 | if (digit < 10) | |
1182 | value[--pos] = (char)(digit + '0'); | |
1183 | else | |
1184 | value[--pos] = (char)((digit - 10) + 'a'); | |
1185 | ||
1186 | val /= 16; | |
1187 | width--; | |
1188 | } | |
1189 | ||
1190 | for (; width > 0; width--) | |
1191 | value[--pos] = '0'; | |
1192 | ||
f211b8c0 | 1193 | string_appendn (decl, &(value[pos]), sizeof(value) - pos); |
b55f9678 IB |
1194 | } |
1195 | string_append (decl, "'"); | |
b55f9678 IB |
1196 | } |
1197 | else if (type == 'b') | |
1198 | { | |
1199 | /* Parse boolean value. */ | |
7ade7fba | 1200 | unsigned long val; |
b55f9678 | 1201 | |
d7e2ebe7 IB |
1202 | mangled = dlang_number (mangled, &val); |
1203 | if (mangled == NULL) | |
b55f9678 IB |
1204 | return NULL; |
1205 | ||
1206 | string_append (decl, val ? "true" : "false"); | |
b55f9678 IB |
1207 | } |
1208 | else | |
1209 | { | |
1210 | /* Parse integer value. */ | |
1211 | const char *numptr = mangled; | |
1212 | size_t num = 0; | |
1213 | ||
d7e2ebe7 IB |
1214 | if (! ISDIGIT (*mangled)) |
1215 | return NULL; | |
1216 | ||
b55f9678 IB |
1217 | while (ISDIGIT (*mangled)) |
1218 | { | |
1219 | num++; | |
1220 | mangled++; | |
1221 | } | |
1222 | string_appendn (decl, numptr, num); | |
1223 | ||
1224 | /* Append suffix. */ | |
1225 | switch (type) | |
1226 | { | |
1227 | case 'h': /* ubyte */ | |
1228 | case 't': /* ushort */ | |
1229 | case 'k': /* uint */ | |
1230 | string_append (decl, "u"); | |
1231 | break; | |
1232 | case 'l': /* long */ | |
1233 | string_append (decl, "L"); | |
1234 | break; | |
1235 | case 'm': /* ulong */ | |
1236 | string_append (decl, "uL"); | |
1237 | break; | |
1238 | } | |
1239 | } | |
1240 | ||
1241 | return mangled; | |
1242 | } | |
1243 | ||
1244 | /* Extract the floating-point value from MANGLED and append it to DECL. | |
1245 | Return the remaining string on success or NULL on failure. */ | |
1246 | static const char * | |
1247 | dlang_parse_real (string *decl, const char *mangled) | |
1248 | { | |
b55f9678 IB |
1249 | /* Handle NAN and +-INF. */ |
1250 | if (strncmp (mangled, "NAN", 3) == 0) | |
1251 | { | |
1252 | string_append (decl, "NaN"); | |
1253 | mangled += 3; | |
1254 | return mangled; | |
1255 | } | |
1256 | else if (strncmp (mangled, "INF", 3) == 0) | |
1257 | { | |
1258 | string_append (decl, "Inf"); | |
1259 | mangled += 3; | |
1260 | return mangled; | |
1261 | } | |
1262 | else if (strncmp (mangled, "NINF", 4) == 0) | |
1263 | { | |
1264 | string_append (decl, "-Inf"); | |
1265 | mangled += 4; | |
1266 | return mangled; | |
1267 | } | |
1268 | ||
1269 | /* Hexadecimal prefix and leading bit. */ | |
1270 | if (*mangled == 'N') | |
1271 | { | |
d7e2ebe7 | 1272 | string_append (decl, "-"); |
b55f9678 IB |
1273 | mangled++; |
1274 | } | |
1275 | ||
1276 | if (!ISXDIGIT (*mangled)) | |
1277 | return NULL; | |
1278 | ||
d7e2ebe7 IB |
1279 | string_append (decl, "0x"); |
1280 | string_appendn (decl, mangled, 1); | |
1281 | string_append (decl, "."); | |
b55f9678 IB |
1282 | mangled++; |
1283 | ||
1284 | /* Significand. */ | |
1285 | while (ISXDIGIT (*mangled)) | |
1286 | { | |
d7e2ebe7 | 1287 | string_appendn (decl, mangled, 1); |
b55f9678 IB |
1288 | mangled++; |
1289 | } | |
1290 | ||
1291 | /* Exponent. */ | |
1292 | if (*mangled != 'P') | |
1293 | return NULL; | |
1294 | ||
d7e2ebe7 | 1295 | string_append (decl, "p"); |
b55f9678 IB |
1296 | mangled++; |
1297 | ||
1298 | if (*mangled == 'N') | |
1299 | { | |
d7e2ebe7 | 1300 | string_append (decl, "-"); |
b55f9678 IB |
1301 | mangled++; |
1302 | } | |
1303 | ||
1304 | while (ISDIGIT (*mangled)) | |
1305 | { | |
d7e2ebe7 | 1306 | string_appendn (decl, mangled, 1); |
b55f9678 IB |
1307 | mangled++; |
1308 | } | |
1309 | ||
b55f9678 IB |
1310 | return mangled; |
1311 | } | |
1312 | ||
b55f9678 IB |
1313 | /* Extract the string value from MANGLED and append it to DECL. |
1314 | Return the remaining string on success or NULL on failure. */ | |
1315 | static const char * | |
1316 | dlang_parse_string (string *decl, const char *mangled) | |
1317 | { | |
1318 | char type = *mangled; | |
7ade7fba | 1319 | unsigned long len; |
b55f9678 IB |
1320 | |
1321 | mangled++; | |
d7e2ebe7 IB |
1322 | mangled = dlang_number (mangled, &len); |
1323 | if (mangled == NULL || *mangled != '_') | |
b55f9678 IB |
1324 | return NULL; |
1325 | ||
1326 | mangled++; | |
1327 | string_append (decl, "\""); | |
1328 | while (len--) | |
1329 | { | |
d7e2ebe7 IB |
1330 | char val; |
1331 | const char *endptr = dlang_hexdigit (mangled, &val); | |
1332 | ||
1333 | if (endptr == NULL) | |
1334 | return NULL; | |
1335 | ||
1336 | /* Sanitize white and non-printable characters. */ | |
1337 | switch (val) | |
b55f9678 | 1338 | { |
d7e2ebe7 IB |
1339 | case ' ': |
1340 | string_append (decl, " "); | |
1341 | break; | |
1342 | case '\t': | |
1343 | string_append (decl, "\\t"); | |
1344 | break; | |
1345 | case '\n': | |
1346 | string_append (decl, "\\n"); | |
1347 | break; | |
1348 | case '\r': | |
1349 | string_append (decl, "\\r"); | |
1350 | break; | |
1351 | case '\f': | |
1352 | string_append (decl, "\\f"); | |
1353 | break; | |
1354 | case '\v': | |
1355 | string_append (decl, "\\v"); | |
1356 | break; | |
f91ca6bc | 1357 | |
d7e2ebe7 IB |
1358 | default: |
1359 | if (ISPRINT (val)) | |
1360 | string_appendn (decl, &val, 1); | |
1361 | else | |
f91ca6bc | 1362 | { |
d7e2ebe7 IB |
1363 | string_append (decl, "\\x"); |
1364 | string_appendn (decl, mangled, 2); | |
f91ca6bc | 1365 | } |
b55f9678 | 1366 | } |
b55f9678 | 1367 | |
d7e2ebe7 | 1368 | mangled = endptr; |
b55f9678 IB |
1369 | } |
1370 | string_append (decl, "\""); | |
1371 | ||
1372 | if (type != 'a') | |
1373 | string_appendn (decl, &type, 1); | |
1374 | ||
1375 | return mangled; | |
1376 | } | |
1377 | ||
1378 | /* Extract the static array value from MANGLED and append it to DECL. | |
1379 | Return the remaining string on success or NULL on failure. */ | |
1380 | static const char * | |
1381 | dlang_parse_arrayliteral (string *decl, const char *mangled) | |
1382 | { | |
7ade7fba | 1383 | unsigned long elements; |
b55f9678 | 1384 | |
d7e2ebe7 IB |
1385 | mangled = dlang_number (mangled, &elements); |
1386 | if (mangled == NULL) | |
b55f9678 IB |
1387 | return NULL; |
1388 | ||
b55f9678 IB |
1389 | string_append (decl, "["); |
1390 | while (elements--) | |
1391 | { | |
1392 | mangled = dlang_value (decl, mangled, NULL, '\0'); | |
f211b8c0 NC |
1393 | if (mangled == NULL) |
1394 | return NULL; | |
1395 | ||
b55f9678 IB |
1396 | if (elements != 0) |
1397 | string_append (decl, ", "); | |
1398 | } | |
1399 | ||
1400 | string_append (decl, "]"); | |
1401 | return mangled; | |
1402 | } | |
1403 | ||
1404 | /* Extract the associative array value from MANGLED and append it to DECL. | |
1405 | Return the remaining string on success or NULL on failure. */ | |
1406 | static const char * | |
1407 | dlang_parse_assocarray (string *decl, const char *mangled) | |
1408 | { | |
7ade7fba | 1409 | unsigned long elements; |
b55f9678 | 1410 | |
d7e2ebe7 IB |
1411 | mangled = dlang_number (mangled, &elements); |
1412 | if (mangled == NULL) | |
b55f9678 IB |
1413 | return NULL; |
1414 | ||
b55f9678 IB |
1415 | string_append (decl, "["); |
1416 | while (elements--) | |
1417 | { | |
1418 | mangled = dlang_value (decl, mangled, NULL, '\0'); | |
f211b8c0 NC |
1419 | if (mangled == NULL) |
1420 | return NULL; | |
1421 | ||
b55f9678 IB |
1422 | string_append (decl, ":"); |
1423 | mangled = dlang_value (decl, mangled, NULL, '\0'); | |
f211b8c0 NC |
1424 | if (mangled == NULL) |
1425 | return NULL; | |
b55f9678 IB |
1426 | |
1427 | if (elements != 0) | |
1428 | string_append (decl, ", "); | |
1429 | } | |
1430 | ||
1431 | string_append (decl, "]"); | |
1432 | return mangled; | |
1433 | } | |
1434 | ||
1435 | /* Extract the struct literal value for NAME from MANGLED and append it to DECL. | |
1436 | Return the remaining string on success or NULL on failure. */ | |
1437 | static const char * | |
1438 | dlang_parse_structlit (string *decl, const char *mangled, const char *name) | |
1439 | { | |
7ade7fba | 1440 | unsigned long args; |
b55f9678 | 1441 | |
d7e2ebe7 IB |
1442 | mangled = dlang_number (mangled, &args); |
1443 | if (mangled == NULL) | |
b55f9678 IB |
1444 | return NULL; |
1445 | ||
b55f9678 IB |
1446 | if (name != NULL) |
1447 | string_append (decl, name); | |
1448 | ||
1449 | string_append (decl, "("); | |
1450 | while (args--) | |
1451 | { | |
1452 | mangled = dlang_value (decl, mangled, NULL, '\0'); | |
f211b8c0 NC |
1453 | if (mangled == NULL) |
1454 | return NULL; | |
1455 | ||
b55f9678 IB |
1456 | if (args != 0) |
1457 | string_append (decl, ", "); | |
1458 | } | |
1459 | ||
1460 | string_append (decl, ")"); | |
1461 | return mangled; | |
1462 | } | |
1463 | ||
1464 | /* Extract the value from MANGLED and append it to DECL. | |
1465 | Return the remaining string on success or NULL on failure. */ | |
1466 | static const char * | |
1467 | dlang_value (string *decl, const char *mangled, const char *name, char type) | |
1468 | { | |
1469 | if (mangled == NULL || *mangled == '\0') | |
f91ca6bc | 1470 | return NULL; |
b55f9678 IB |
1471 | |
1472 | switch (*mangled) | |
1473 | { | |
1474 | /* Null value. */ | |
1475 | case 'n': | |
1476 | mangled++; | |
1477 | string_append (decl, "null"); | |
1478 | break; | |
1479 | ||
1480 | /* Integral values. */ | |
1481 | case 'N': | |
1482 | mangled++; | |
1483 | string_append (decl, "-"); | |
1484 | mangled = dlang_parse_integer (decl, mangled, type); | |
1485 | break; | |
1486 | ||
1487 | case 'i': | |
1488 | mangled++; | |
b55f9678 | 1489 | /* Fall through */ |
d7e2ebe7 IB |
1490 | |
1491 | /* There really should always be an `i' before encoded numbers, but there | |
1492 | wasn't in early versions of D2, so this case range must remain for | |
1493 | backwards compatibility. */ | |
b55f9678 IB |
1494 | case '0': case '1': case '2': case '3': case '4': |
1495 | case '5': case '6': case '7': case '8': case '9': | |
1496 | mangled = dlang_parse_integer (decl, mangled, type); | |
1497 | break; | |
1498 | ||
1499 | /* Real value. */ | |
1500 | case 'e': | |
1501 | mangled++; | |
1502 | mangled = dlang_parse_real (decl, mangled); | |
1503 | break; | |
1504 | ||
1505 | /* Complex value. */ | |
1506 | case 'c': | |
1507 | mangled++; | |
1508 | mangled = dlang_parse_real (decl, mangled); | |
1509 | string_append (decl, "+"); | |
1510 | if (mangled == NULL || *mangled != 'c') | |
1511 | return NULL; | |
1512 | mangled++; | |
1513 | mangled = dlang_parse_real (decl, mangled); | |
1514 | string_append (decl, "i"); | |
1515 | break; | |
1516 | ||
1517 | /* String values. */ | |
1518 | case 'a': /* UTF8 */ | |
1519 | case 'w': /* UTF16 */ | |
1520 | case 'd': /* UTF32 */ | |
1521 | mangled = dlang_parse_string (decl, mangled); | |
1522 | break; | |
1523 | ||
1524 | /* Array values. */ | |
1525 | case 'A': | |
1526 | mangled++; | |
1527 | if (type == 'H') | |
1528 | mangled = dlang_parse_assocarray (decl, mangled); | |
1529 | else | |
1530 | mangled = dlang_parse_arrayliteral (decl, mangled); | |
1531 | break; | |
1532 | ||
1533 | /* Struct values. */ | |
1534 | case 'S': | |
1535 | mangled++; | |
1536 | mangled = dlang_parse_structlit (decl, mangled, name); | |
1537 | break; | |
1538 | ||
1539 | default: | |
1540 | return NULL; | |
1541 | } | |
1542 | ||
1543 | return mangled; | |
1544 | } | |
1545 | ||
d7e2ebe7 IB |
1546 | /* Extract and demangle the symbol in MANGLED and append it to DECL. |
1547 | Returns the remaining signature on success or NULL on failure. */ | |
1548 | static const char * | |
727b7b18 | 1549 | dlang_parse_mangle (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 | 1550 | { |
d7e2ebe7 IB |
1551 | /* A D mangled symbol is comprised of both scope and type information. |
1552 | ||
1553 | MangleName: | |
1554 | _D QualifiedName Type | |
d7e2ebe7 IB |
1555 | _D QualifiedName Z |
1556 | ^ | |
1557 | The caller should have guaranteed that the start pointer is at the | |
1558 | above location. | |
727b7b18 L |
1559 | Note that type is never a function type, but only the return type of |
1560 | a function or the type of a variable. | |
d7e2ebe7 IB |
1561 | */ |
1562 | mangled += 2; | |
b55f9678 | 1563 | |
727b7b18 | 1564 | mangled = dlang_parse_qualified (decl, mangled, info, 1); |
d7e2ebe7 IB |
1565 | |
1566 | if (mangled != NULL) | |
b55f9678 | 1567 | { |
d7e2ebe7 IB |
1568 | /* Artificial symbols end with 'Z' and have no type. */ |
1569 | if (*mangled == 'Z') | |
1570 | mangled++; | |
1571 | else | |
1572 | { | |
727b7b18 L |
1573 | /* Discard the declaration or return type. */ |
1574 | string type; | |
d7e2ebe7 | 1575 | |
727b7b18 L |
1576 | string_init (&type); |
1577 | mangled = dlang_type (&type, mangled, info); | |
1578 | string_delete (&type); | |
d7e2ebe7 | 1579 | } |
f91ca6bc IB |
1580 | } |
1581 | ||
d7e2ebe7 | 1582 | return mangled; |
b55f9678 IB |
1583 | } |
1584 | ||
d7e2ebe7 | 1585 | /* Extract and demangle the qualified symbol in MANGLED and append it to DECL. |
727b7b18 | 1586 | SUFFIX_MODIFIERS is 1 if we are printing modifiers on this after the symbol. |
b55f9678 IB |
1587 | Returns the remaining signature on success or NULL on failure. */ |
1588 | static const char * | |
d7e2ebe7 | 1589 | dlang_parse_qualified (string *decl, const char *mangled, |
727b7b18 | 1590 | struct dlang_info *info, int suffix_modifiers) |
b55f9678 | 1591 | { |
d7e2ebe7 IB |
1592 | /* Qualified names are identifiers separated by their encoded length. |
1593 | Nested functions also encode their argument types without specifying | |
1594 | what they return. | |
1595 | ||
1596 | QualifiedName: | |
727b7b18 L |
1597 | SymbolFunctionName |
1598 | SymbolFunctionName QualifiedName | |
d7e2ebe7 | 1599 | ^ |
727b7b18 L |
1600 | |
1601 | SymbolFunctionName: | |
1602 | SymbolName | |
1603 | SymbolName TypeFunctionNoReturn | |
1604 | SymbolName M TypeFunctionNoReturn | |
1605 | SymbolName M TypeModifiers TypeFunctionNoReturn | |
1606 | ||
d7e2ebe7 IB |
1607 | The start pointer should be at the above location. |
1608 | */ | |
b55f9678 IB |
1609 | size_t n = 0; |
1610 | do | |
1611 | { | |
1612 | if (n++) | |
1613 | string_append (decl, "."); | |
1614 | ||
d7e2ebe7 IB |
1615 | /* Skip over anonymous symbols. */ |
1616 | while (*mangled == '0') | |
1617 | mangled++; | |
1618 | ||
727b7b18 | 1619 | mangled = dlang_identifier (decl, mangled, info); |
b55f9678 | 1620 | |
d7e2ebe7 | 1621 | /* Consume the encoded arguments. However if this is not followed by the |
727b7b18 L |
1622 | next encoded length or mangle type, then this is not a continuation of |
1623 | a qualified name, in which case we backtrack and return the current | |
1624 | unconsumed position of the mangled decl. */ | |
d7e2ebe7 | 1625 | if (mangled && (*mangled == 'M' || dlang_call_convention_p (mangled))) |
b55f9678 | 1626 | { |
727b7b18 | 1627 | string mods; |
d7e2ebe7 IB |
1628 | const char *start = mangled; |
1629 | int saved = string_length (decl); | |
b55f9678 | 1630 | |
727b7b18 L |
1631 | /* Save the type modifiers for appending at the end if needed. */ |
1632 | string_init (&mods); | |
1633 | ||
d7e2ebe7 | 1634 | /* Skip over 'this' parameter and type modifiers. */ |
b55f9678 | 1635 | if (*mangled == 'M') |
f91ca6bc | 1636 | { |
d7e2ebe7 | 1637 | mangled++; |
727b7b18 | 1638 | mangled = dlang_type_modifiers (&mods, mangled); |
d7e2ebe7 | 1639 | string_setlength (decl, saved); |
f91ca6bc IB |
1640 | } |
1641 | ||
727b7b18 L |
1642 | mangled = dlang_function_type_noreturn (decl, NULL, NULL, |
1643 | mangled, info); | |
1644 | if (suffix_modifiers) | |
1645 | string_appendn (decl, mods.b, string_length (&mods)); | |
b55f9678 | 1646 | |
727b7b18 | 1647 | if (mangled == NULL || *mangled == '\0') |
b55f9678 | 1648 | { |
d7e2ebe7 | 1649 | /* Did not match the rule we were looking for. */ |
f91ca6bc | 1650 | mangled = start; |
d7e2ebe7 | 1651 | string_setlength (decl, saved); |
b55f9678 | 1652 | } |
727b7b18 L |
1653 | |
1654 | string_delete (&mods); | |
b55f9678 IB |
1655 | } |
1656 | } | |
727b7b18 | 1657 | while (mangled && dlang_symbol_name_p (mangled, info)); |
b55f9678 IB |
1658 | |
1659 | return mangled; | |
1660 | } | |
1661 | ||
1662 | /* Demangle the tuple from MANGLED and append it to DECL. | |
1663 | Return the remaining string on success or NULL on failure. */ | |
1664 | static const char * | |
727b7b18 | 1665 | dlang_parse_tuple (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 | 1666 | { |
7ade7fba | 1667 | unsigned long elements; |
b55f9678 | 1668 | |
d7e2ebe7 IB |
1669 | mangled = dlang_number (mangled, &elements); |
1670 | if (mangled == NULL) | |
b55f9678 IB |
1671 | return NULL; |
1672 | ||
b55f9678 IB |
1673 | string_append (decl, "Tuple!("); |
1674 | ||
1675 | while (elements--) | |
1676 | { | |
727b7b18 | 1677 | mangled = dlang_type (decl, mangled, info); |
f211b8c0 NC |
1678 | if (mangled == NULL) |
1679 | return NULL; | |
1680 | ||
b55f9678 IB |
1681 | if (elements != 0) |
1682 | string_append (decl, ", "); | |
1683 | } | |
1684 | ||
1685 | string_append (decl, ")"); | |
1686 | return mangled; | |
1687 | } | |
1688 | ||
727b7b18 L |
1689 | /* Demangle the template symbol parameter from MANGLED and append it to DECL. |
1690 | Return the remaining string on success or NULL on failure. */ | |
1691 | static const char * | |
1692 | dlang_template_symbol_param (string *decl, const char *mangled, | |
1693 | struct dlang_info *info) | |
1694 | { | |
1695 | if (strncmp (mangled, "_D", 2) == 0 | |
1696 | && dlang_symbol_name_p (mangled + 2, info)) | |
1697 | return dlang_parse_mangle (decl, mangled, info); | |
1698 | ||
1699 | if (*mangled == 'Q') | |
1700 | return dlang_parse_qualified (decl, mangled, info, 0); | |
1701 | ||
7ade7fba | 1702 | unsigned long len; |
727b7b18 L |
1703 | const char *endptr = dlang_number (mangled, &len); |
1704 | ||
1705 | if (endptr == NULL || len == 0) | |
1706 | return NULL; | |
1707 | ||
1708 | /* In template parameter symbols generated by the frontend up to 2.076, | |
1709 | the symbol length is encoded and the first character of the mangled | |
1710 | name can be a digit. This causes ambiguity issues because the digits | |
1711 | of the two numbers are adjacent. */ | |
1712 | long psize = len; | |
1713 | const char *pend; | |
1714 | int saved = string_length (decl); | |
1715 | ||
1716 | /* Work backwards until a match is found. */ | |
1717 | for (pend = endptr; endptr != NULL; pend--) | |
1718 | { | |
1719 | mangled = pend; | |
1720 | ||
1721 | /* Reached the beginning of the pointer to the name length, | |
1722 | try parsing the entire symbol. */ | |
1723 | if (psize == 0) | |
1724 | { | |
1725 | psize = len; | |
1726 | pend = endptr; | |
1727 | endptr = NULL; | |
1728 | } | |
1729 | ||
1730 | /* Check whether template parameter is a function with a valid | |
1731 | return type or an untyped identifier. */ | |
1732 | if (dlang_symbol_name_p (mangled, info)) | |
1733 | mangled = dlang_parse_qualified (decl, mangled, info, 0); | |
1734 | else if (strncmp (mangled, "_D", 2) == 0 | |
1735 | && dlang_symbol_name_p (mangled + 2, info)) | |
1736 | mangled = dlang_parse_mangle (decl, mangled, info); | |
1737 | ||
1738 | /* Check for name length mismatch. */ | |
1739 | if (mangled && (endptr == NULL || (mangled - pend) == psize)) | |
1740 | return mangled; | |
1741 | ||
1742 | psize /= 10; | |
1743 | string_setlength (decl, saved); | |
1744 | } | |
1745 | ||
1746 | /* No match on any combinations. */ | |
1747 | return NULL; | |
1748 | } | |
1749 | ||
b55f9678 IB |
1750 | /* Demangle the argument list from MANGLED and append it to DECL. |
1751 | Return the remaining string on success or NULL on failure. */ | |
1752 | static const char * | |
727b7b18 | 1753 | dlang_template_args (string *decl, const char *mangled, struct dlang_info *info) |
b55f9678 IB |
1754 | { |
1755 | size_t n = 0; | |
1756 | ||
1757 | while (mangled && *mangled != '\0') | |
1758 | { | |
1759 | switch (*mangled) | |
1760 | { | |
1761 | case 'Z': /* End of parameter list. */ | |
1762 | mangled++; | |
1763 | return mangled; | |
1764 | } | |
1765 | ||
1766 | if (n++) | |
1767 | string_append (decl, ", "); | |
1768 | ||
f91ca6bc IB |
1769 | /* Skip over specialised template prefix. */ |
1770 | if (*mangled == 'H') | |
1771 | mangled++; | |
1772 | ||
b55f9678 IB |
1773 | switch (*mangled) |
1774 | { | |
1775 | case 'S': /* Symbol parameter. */ | |
1776 | mangled++; | |
727b7b18 | 1777 | mangled = dlang_template_symbol_param (decl, mangled, info); |
b55f9678 IB |
1778 | break; |
1779 | case 'T': /* Type parameter. */ | |
1780 | mangled++; | |
727b7b18 | 1781 | mangled = dlang_type (decl, mangled, info); |
b55f9678 IB |
1782 | break; |
1783 | case 'V': /* Value parameter. */ | |
1784 | { | |
1785 | string name; | |
1786 | char type; | |
1787 | ||
1788 | /* Peek at the type. */ | |
1789 | mangled++; | |
1790 | type = *mangled; | |
1791 | ||
727b7b18 L |
1792 | if (type == 'Q') |
1793 | { | |
1794 | /* Value type is a back reference, peek at the real type. */ | |
1795 | const char *backref; | |
1796 | if (dlang_backref (mangled, &backref, info) == NULL) | |
1797 | return NULL; | |
1798 | ||
1799 | type = *backref; | |
1800 | } | |
1801 | ||
b55f9678 IB |
1802 | /* In the few instances where the type is actually desired in |
1803 | the output, it should precede the value from dlang_value. */ | |
1804 | string_init (&name); | |
727b7b18 | 1805 | mangled = dlang_type (&name, mangled, info); |
b55f9678 IB |
1806 | string_need (&name, 1); |
1807 | *(name.p) = '\0'; | |
1808 | ||
1809 | mangled = dlang_value (decl, mangled, name.b, type); | |
1810 | string_delete (&name); | |
1811 | break; | |
1812 | } | |
727b7b18 L |
1813 | case 'X': /* Externally mangled parameter. */ |
1814 | { | |
7ade7fba | 1815 | unsigned long len; |
727b7b18 | 1816 | const char *endptr; |
b55f9678 | 1817 | |
727b7b18 L |
1818 | mangled++; |
1819 | endptr = dlang_number (mangled, &len); | |
7ade7fba | 1820 | if (endptr == NULL || strlen (endptr) < len) |
727b7b18 L |
1821 | return NULL; |
1822 | ||
1823 | string_appendn (decl, endptr, len); | |
1824 | mangled = endptr + len; | |
1825 | break; | |
1826 | } | |
b55f9678 IB |
1827 | default: |
1828 | return NULL; | |
1829 | } | |
1830 | } | |
1831 | ||
1832 | return mangled; | |
1833 | } | |
1834 | ||
1835 | /* Extract and demangle the template symbol in MANGLED, expected to | |
727b7b18 | 1836 | be made up of LEN characters (-1 if unknown), and append it to DECL. |
b55f9678 IB |
1837 | Returns the remaining signature on success or NULL on failure. */ |
1838 | static const char * | |
727b7b18 | 1839 | dlang_parse_template (string *decl, const char *mangled, |
7ade7fba | 1840 | struct dlang_info *info, unsigned long len) |
b55f9678 IB |
1841 | { |
1842 | const char *start = mangled; | |
727b7b18 | 1843 | string args; |
b55f9678 IB |
1844 | |
1845 | /* Template instance names have the types and values of its parameters | |
1846 | encoded into it. | |
1847 | ||
1848 | TemplateInstanceName: | |
1849 | Number __T LName TemplateArgs Z | |
d7e2ebe7 | 1850 | Number __U LName TemplateArgs Z |
b55f9678 IB |
1851 | ^ |
1852 | The start pointer should be at the above location, and LEN should be | |
1853 | the value of the decoded number. | |
1854 | */ | |
d7e2ebe7 IB |
1855 | |
1856 | /* Template symbol. */ | |
727b7b18 | 1857 | if (!dlang_symbol_name_p (mangled + 3, info) || mangled[3] == '0') |
b55f9678 IB |
1858 | return NULL; |
1859 | ||
1860 | mangled += 3; | |
1861 | ||
1862 | /* Template identifier. */ | |
727b7b18 | 1863 | mangled = dlang_identifier (decl, mangled, info); |
b55f9678 IB |
1864 | |
1865 | /* Template arguments. */ | |
727b7b18 L |
1866 | string_init (&args); |
1867 | mangled = dlang_template_args (&args, mangled, info); | |
1868 | ||
b55f9678 | 1869 | string_append (decl, "!("); |
727b7b18 | 1870 | string_appendn (decl, args.b, string_length (&args)); |
b55f9678 IB |
1871 | string_append (decl, ")"); |
1872 | ||
727b7b18 L |
1873 | string_delete (&args); |
1874 | ||
b55f9678 | 1875 | /* Check for template name length mismatch. */ |
7ade7fba AM |
1876 | if (len != TEMPLATE_LENGTH_UNKNOWN |
1877 | && mangled | |
1878 | && (unsigned long) (mangled - start) != len) | |
b55f9678 IB |
1879 | return NULL; |
1880 | ||
1881 | return mangled; | |
1882 | } | |
1883 | ||
727b7b18 L |
1884 | /* Initialize the information structure we use to pass around information. */ |
1885 | static void | |
1886 | dlang_demangle_init_info (const char *mangled, int last_backref, | |
1887 | struct dlang_info *info) | |
1888 | { | |
1889 | info->s = mangled; | |
1890 | info->last_backref = last_backref; | |
1891 | } | |
1892 | ||
b55f9678 IB |
1893 | /* Extract and demangle the symbol in MANGLED. Returns the demangled |
1894 | signature on success or NULL on failure. */ | |
1895 | ||
1896 | char * | |
1897 | dlang_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) | |
1898 | { | |
1899 | string decl; | |
1900 | char *demangled = NULL; | |
1901 | ||
1902 | if (mangled == NULL || *mangled == '\0') | |
1903 | return NULL; | |
1904 | ||
1905 | if (strncmp (mangled, "_D", 2) != 0) | |
1906 | return NULL; | |
1907 | ||
1908 | string_init (&decl); | |
1909 | ||
1910 | if (strcmp (mangled, "_Dmain") == 0) | |
1911 | { | |
1912 | string_append (&decl, "D main"); | |
1913 | } | |
1914 | else | |
1915 | { | |
727b7b18 L |
1916 | struct dlang_info info; |
1917 | ||
1918 | dlang_demangle_init_info (mangled, strlen (mangled), &info); | |
1919 | mangled = dlang_parse_mangle (&decl, mangled, &info); | |
1920 | ||
1921 | /* Check that the entire symbol was successfully demangled. */ | |
1922 | if (mangled == NULL || *mangled != '\0') | |
b55f9678 IB |
1923 | string_delete (&decl); |
1924 | } | |
1925 | ||
1926 | if (string_length (&decl) > 0) | |
1927 | { | |
1928 | string_need (&decl, 1); | |
1929 | *(decl.p) = '\0'; | |
1930 | demangled = decl.b; | |
1931 | } | |
1932 | ||
1933 | return demangled; | |
1934 | } | |
1935 |