PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/d/phobos/std/demangle.d

https://bitbucket.org/goshawk/gdc/
D | 523 lines | 385 code | 66 blank | 72 comment | 59 complexity | 2b87616192e0a7c977a3e1c044e40829 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. // Written in the D programming language.
  2. /*
  3. * Placed into the Public Domain.
  4. */
  5. /* NOTE: This file has been patched from the original DMD distribution to
  6. work with the GDC compiler.
  7. Modified by David Friedman, November 2005
  8. */
  9. /****
  10. * Demangle D mangled names.
  11. * Source: $(PHOBOSSRC std/_demangle.d)
  12. * Macros:
  13. * WIKI = Phobos/StdDemangle
  14. */
  15. /* Authors:
  16. * Walter Bright, Digital Mars, www.digitalmars.com
  17. * Thomas Kuehne
  18. * Frits van Bommel
  19. */
  20. module std.demangle;
  21. //debug=demangle; // uncomment to turn on debugging printf's
  22. private import std.ctype;
  23. private import std.string;
  24. private import std.utf;
  25. private import std.stdio;
  26. private class MangleException : Exception
  27. {
  28. this()
  29. {
  30. super("MangleException");
  31. }
  32. }
  33. /*****************************
  34. * Demangle D mangled names.
  35. *
  36. * If it is not a D mangled name, it returns its argument name.
  37. * Example:
  38. * This program reads standard in and writes it to standard out,
  39. * pretty-printing any found D mangled names.
  40. -------------------
  41. import std.stdio;
  42. import std.ctype;
  43. import std.demangle;
  44. int main()
  45. { char[] buffer;
  46. bool inword;
  47. int c;
  48. while ((c = fgetc(stdin)) != EOF)
  49. {
  50. if (inword)
  51. {
  52. if (c == '_' || isalnum(c))
  53. buffer ~= cast(char) c;
  54. else
  55. {
  56. inword = false;
  57. writef(demangle(buffer), cast(char) c);
  58. }
  59. }
  60. else
  61. { if (c == '_' || isalpha(c))
  62. { inword = true;
  63. buffer.length = 0;
  64. buffer ~= cast(char) c;
  65. }
  66. else
  67. writef(cast(char) c);
  68. }
  69. }
  70. if (inword)
  71. writef(demangle(buffer));
  72. return 0;
  73. }
  74. -------------------
  75. */
  76. string demangle(string name)
  77. {
  78. size_t ni = 2;
  79. string delegate() fparseTemplateInstanceName;
  80. static void error()
  81. {
  82. //writefln("error()");
  83. throw new MangleException();
  84. }
  85. static ubyte ascii2hex(char c)
  86. {
  87. if (!isxdigit(c))
  88. error();
  89. return cast(ubyte)
  90. ( (c >= 'a') ? c - 'a' + 10 :
  91. (c >= 'A') ? c - 'A' + 10 :
  92. c - '0'
  93. );
  94. }
  95. size_t parseNumber()
  96. {
  97. //writefln("parseNumber() %d", ni);
  98. size_t result;
  99. while (ni < name.length && isdigit(name[ni]))
  100. { int i = name[ni] - '0';
  101. if (result > (size_t.max - i) / 10)
  102. error();
  103. result = result * 10 + i;
  104. ni++;
  105. }
  106. return result;
  107. }
  108. string parseSymbolName()
  109. {
  110. //writefln("parseSymbolName() %d", ni);
  111. size_t i = parseNumber();
  112. if (ni + i > name.length)
  113. error();
  114. string result;
  115. if (i >= 5 &&
  116. name[ni] == '_' &&
  117. name[ni + 1] == '_' &&
  118. name[ni + 2] == 'T')
  119. {
  120. size_t nisave = ni;
  121. bool err;
  122. ni += 3;
  123. try
  124. {
  125. result = fparseTemplateInstanceName();
  126. if (ni != nisave + i)
  127. err = true;
  128. }
  129. catch (MangleException me)
  130. {
  131. err = true;
  132. }
  133. ni = nisave;
  134. if (err)
  135. goto L1;
  136. goto L2;
  137. }
  138. L1:
  139. result = name[ni .. ni + i];
  140. L2:
  141. ni += i;
  142. return result;
  143. }
  144. string parseQualifiedName()
  145. {
  146. //writefln("parseQualifiedName() %d", ni);
  147. string result;
  148. while (ni < name.length && isdigit(name[ni]))
  149. {
  150. if (result.length)
  151. result ~= ".";
  152. result ~= parseSymbolName();
  153. }
  154. return result;
  155. }
  156. string parseType(string identifier = null)
  157. {
  158. //writefln("parseType() %d", ni);
  159. int isdelegate = 0;
  160. bool hasthisptr = false; /// For function/delegate types: expects a 'this' pointer as last argument
  161. Lagain:
  162. if (ni >= name.length)
  163. error();
  164. string p;
  165. switch (name[ni++])
  166. {
  167. case 'v': p = "void"; goto L1;
  168. case 'b': p = "bool"; goto L1;
  169. case 'g': p = "byte"; goto L1;
  170. case 'h': p = "ubyte"; goto L1;
  171. case 's': p = "short"; goto L1;
  172. case 't': p = "ushort"; goto L1;
  173. case 'i': p = "int"; goto L1;
  174. case 'k': p = "uint"; goto L1;
  175. case 'l': p = "long"; goto L1;
  176. case 'm': p = "ulong"; goto L1;
  177. case 'f': p = "float"; goto L1;
  178. case 'd': p = "double"; goto L1;
  179. case 'e': p = "real"; goto L1;
  180. case 'o': p = "ifloat"; goto L1;
  181. case 'p': p = "idouble"; goto L1;
  182. case 'j': p = "ireal"; goto L1;
  183. case 'q': p = "cfloat"; goto L1;
  184. case 'r': p = "cdouble"; goto L1;
  185. case 'c': p = "creal"; goto L1;
  186. case 'a': p = "char"; goto L1;
  187. case 'u': p = "wchar"; goto L1;
  188. case 'w': p = "dchar"; goto L1;
  189. case 'A': // dynamic array
  190. p = parseType() ~ "[]";
  191. goto L1;
  192. case 'P': // pointer
  193. p = parseType() ~ "*";
  194. goto L1;
  195. case 'G': // static array
  196. { size_t ns = ni;
  197. parseNumber();
  198. size_t ne = ni;
  199. p = parseType() ~ "[" ~ name[ns .. ne] ~ "]";
  200. goto L1;
  201. }
  202. case 'H': // associative array
  203. p = parseType();
  204. p = parseType() ~ "[" ~ p ~ "]";
  205. goto L1;
  206. case 'D': // delegate
  207. isdelegate = 1;
  208. goto Lagain;
  209. case 'M':
  210. hasthisptr = true;
  211. goto Lagain;
  212. case 'F': // D function
  213. case 'U': // C function
  214. case 'W': // Windows function
  215. case 'V': // Pascal function
  216. case 'R': // C++ function
  217. { char mc = name[ni - 1];
  218. string args;
  219. while (1)
  220. {
  221. if (ni >= name.length)
  222. error();
  223. char c = name[ni];
  224. if (c == 'Z')
  225. break;
  226. if (c == 'X')
  227. {
  228. if (!args.length) error();
  229. args ~= " ...";
  230. break;
  231. }
  232. if (args.length)
  233. args ~= ", ";
  234. switch (c)
  235. {
  236. case 'J':
  237. args ~= "out ";
  238. ni++;
  239. goto default;
  240. case 'K':
  241. args ~= "inout ";
  242. ni++;
  243. goto default;
  244. case 'L':
  245. args ~= "lazy ";
  246. ni++;
  247. goto default;
  248. default:
  249. args ~= parseType();
  250. continue;
  251. case 'Y':
  252. args ~= "...";
  253. break;
  254. }
  255. break;
  256. }
  257. ni++;
  258. if (!isdelegate && identifier.length)
  259. {
  260. switch (mc)
  261. {
  262. case 'F': p = null; break; // D function
  263. case 'U': p = "extern (C) "; break; // C function
  264. case 'W': p = "extern (Windows) "; break; // Windows function
  265. case 'V': p = "extern (Pascal) "; break; // Pascal function
  266. default: assert(0);
  267. }
  268. p ~= parseType() ~ " " ~ identifier ~ "(" ~ args ~ ")";
  269. return p;
  270. }
  271. p = parseType() ~
  272. (isdelegate ? " delegate(" : " function(") ~
  273. args ~
  274. ")";
  275. isdelegate = 0;
  276. goto L1;
  277. }
  278. case 'C': p = "class "; goto L2;
  279. case 'S': p = "struct "; goto L2;
  280. case 'E': p = "enum "; goto L2;
  281. case 'T': p = "typedef "; goto L2;
  282. L2: p ~= parseQualifiedName();
  283. goto L1;
  284. L1:
  285. if (isdelegate)
  286. error(); // 'D' must be followed by function
  287. if (identifier.length)
  288. p ~= " " ~ identifier;
  289. return p;
  290. default:
  291. size_t i = ni - 1;
  292. ni = name.length;
  293. p = name[i .. length];
  294. goto L1;
  295. }
  296. }
  297. string parseTemplateInstanceName()
  298. {
  299. auto result = parseSymbolName() ~ "!(";
  300. int nargs;
  301. while (1)
  302. { size_t i;
  303. if (ni >= name.length)
  304. error();
  305. if (nargs && name[ni] != 'Z')
  306. result ~= ", ";
  307. nargs++;
  308. switch (name[ni++])
  309. {
  310. case 'T':
  311. result ~= parseType();
  312. continue;
  313. case 'V':
  314. void getReal()
  315. { real r;
  316. ubyte *p = cast(ubyte *)&r;
  317. if (ni + real.sizeof * 2 > name.length)
  318. error();
  319. for (i = 0; i < real.sizeof; i++)
  320. { ubyte b;
  321. b = cast(ubyte)
  322. (
  323. (ascii2hex(name[ni + i * 2]) << 4) +
  324. ascii2hex(name[ni + i * 2 + 1])
  325. );
  326. p[i] = b;
  327. }
  328. result ~= format(r);
  329. ni += 10 * 2;
  330. }
  331. result ~= parseType() ~ " ";
  332. if (ni >= name.length)
  333. error();
  334. switch (name[ni++])
  335. {
  336. case '0': case '1': case '2': case '3': case '4':
  337. case '5': case '6': case '7': case '8': case '9':
  338. i = ni - 1;
  339. while (ni < name.length && isdigit(name[ni]))
  340. ni++;
  341. result ~= name[i .. ni];
  342. break;
  343. case 'N':
  344. i = ni;
  345. while (ni < name.length && isdigit(name[ni]))
  346. ni++;
  347. if (i == ni)
  348. error();
  349. result ~= "-" ~ name[i .. ni];
  350. break;
  351. case 'n':
  352. result ~= "null";
  353. break;
  354. case 'e':
  355. getReal();
  356. break;
  357. case 'c':
  358. getReal();
  359. result ~= '+';
  360. getReal();
  361. result ~= 'i';
  362. break;
  363. case 'a':
  364. case 'w':
  365. case 'd':
  366. { char m = name[ni - 1];
  367. if (m == 'a')
  368. m = 'c';
  369. size_t n = parseNumber();
  370. if (ni >= name.length || name[ni++] != '_' ||
  371. ni + n * 2 > name.length)
  372. error();
  373. result ~= '"';
  374. for (i = 0; i < n; i++)
  375. { char c;
  376. c = cast(char)((ascii2hex(name[ni + i * 2]) << 4) +
  377. ascii2hex(name[ni + i * 2 + 1]));
  378. result ~= c;
  379. }
  380. ni += n * 2;
  381. result ~= '"';
  382. result ~= m;
  383. break;
  384. }
  385. default:
  386. error();
  387. break;
  388. }
  389. continue;
  390. case 'S':
  391. result ~= parseSymbolName();
  392. continue;
  393. case 'Z':
  394. break;
  395. default:
  396. error();
  397. }
  398. break;
  399. }
  400. result ~= ")";
  401. return result;
  402. }
  403. if (name.length < 3 ||
  404. name[0] != '_' ||
  405. name[1] != 'D' ||
  406. !isdigit(name[2]))
  407. {
  408. goto Lnot;
  409. }
  410. fparseTemplateInstanceName = &parseTemplateInstanceName;
  411. try
  412. {
  413. auto result = parseQualifiedName();
  414. result = parseType(result);
  415. while(ni < name.length){
  416. result ~= " . " ~ parseType(parseQualifiedName());
  417. }
  418. if (ni != name.length)
  419. goto Lnot;
  420. return result;
  421. }
  422. catch (MangleException e)
  423. {
  424. }
  425. Lnot:
  426. // Not a recognized D mangled name; so return original
  427. return name;
  428. }
  429. unittest
  430. {
  431. debug(demangle) printf("demangle.demangle.unittest\n");
  432. static string[2][] table =
  433. [
  434. [ "printf", "printf" ],
  435. [ "_foo", "_foo" ],
  436. [ "_D88", "_D88" ],
  437. [ "_D4test3fooAa", "char[] test.foo"],
  438. [ "_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])" ],
  439. [ "_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(class Object)" ],
  440. [ "_D4test2dgDFiYd", "double delegate(int, ...) test.dg" ],
  441. [ "_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, char[5] \"hello\"c, void* null).factorial" ],
  442. [ "_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, cdouble 6.8+3i, char[5] \"hello\"c, void* null).factorial" ],
  443. [ "_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(wchar[3] \"abc\"w, dchar[3] \"def\"d).x" ],
  444. [ "_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy class Object, lazy int delegate(lazy int))"],
  445. [ "_D8demangle4testFAiXi", "int demangle.test(int[] ...)"],
  446. [ "_D8demangle4testFLAiXi", "int demangle.test(lazy int[] ...)"]
  447. ];
  448. foreach (i, name; table)
  449. {
  450. string r = demangle(name[0]);
  451. assert(r == name[1],
  452. "table entry #" ~ toString(i) ~ ": '" ~ name[0] ~ "' demangles as '" ~ r ~ "' but is expected to be '" ~ name[1] ~ "'");
  453. }
  454. }