demangle.d 81 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783
  1. /**
  2. * The demangle module converts mangled D symbols to a representation similar
  3. * to what would have existed in code.
  4. *
  5. * Copyright: Copyright Sean Kelly 2010 - 2014.
  6. * License: Distributed under the
  7. * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
  8. * (See accompanying file LICENSE)
  9. * Authors: Sean Kelly
  10. * Source: $(DRUNTIMESRC core/_demangle.d)
  11. */
  12. module core.demangle;
  13. version (OSX)
  14. version = Darwin;
  15. else version (iOS)
  16. version = Darwin;
  17. else version (TVOS)
  18. version = Darwin;
  19. else version (WatchOS)
  20. version = Darwin;
  21. debug(trace) import core.stdc.stdio : printf;
  22. debug(info) import core.stdc.stdio : printf;
  23. private struct NoHooks
  24. {
  25. // supported hooks
  26. // static bool parseLName(ref Demangle);
  27. // static char[] parseType(ref Demangle, char[])
  28. }
  29. private struct Demangle(Hooks = NoHooks)
  30. {
  31. // NOTE: This implementation currently only works with mangled function
  32. // names as they exist in an object file. Type names mangled via
  33. // the .mangleof property are effectively incomplete as far as the
  34. // ABI is concerned and so are not considered to be mangled symbol
  35. // names.
  36. // NOTE: This implementation builds the demangled buffer in place by
  37. // writing data as it is decoded and then rearranging it later as
  38. // needed. In practice this results in very little data movement,
  39. // and the performance cost is more than offset by the gain from
  40. // not allocating dynamic memory to assemble the name piecemeal.
  41. //
  42. // If the destination buffer is too small, parsing will restart
  43. // with a larger buffer. Since this generally means only one
  44. // allocation during the course of a parsing run, this is still
  45. // faster than assembling the result piecemeal.
  46. pure @safe:
  47. enum AddType { no, yes }
  48. this( return scope const(char)[] buf_, return scope char[] dst_ = null )
  49. {
  50. this( buf_, AddType.yes, dst_ );
  51. }
  52. this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null )
  53. {
  54. buf = buf_;
  55. addType = addType_;
  56. dst = dst_;
  57. }
  58. enum size_t minBufSize = 4000;
  59. const(char)[] buf = null;
  60. char[] dst = null;
  61. size_t pos = 0;
  62. size_t len = 0;
  63. size_t brp = 0; // current back reference pos
  64. AddType addType = AddType.yes;
  65. bool mute = false;
  66. Hooks hooks;
  67. static class ParseException : Exception
  68. {
  69. @safe pure nothrow this( string msg )
  70. {
  71. super( msg );
  72. }
  73. }
  74. static class OverflowException : Exception
  75. {
  76. @safe pure nothrow this( string msg )
  77. {
  78. super( msg );
  79. }
  80. }
  81. static void error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */
  82. {
  83. pragma(inline, false); // tame dmd inliner
  84. //throw new ParseException( msg );
  85. debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
  86. throw __ctfe ? new ParseException(msg)
  87. : cast(ParseException) __traits(initSymbol, ParseException).ptr;
  88. }
  89. static void overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */
  90. {
  91. pragma(inline, false); // tame dmd inliner
  92. //throw new OverflowException( msg );
  93. debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
  94. throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
  95. }
  96. //////////////////////////////////////////////////////////////////////////
  97. // Type Testing and Conversion
  98. //////////////////////////////////////////////////////////////////////////
  99. static bool isAlpha( char val )
  100. {
  101. return ('a' <= val && 'z' >= val) ||
  102. ('A' <= val && 'Z' >= val) ||
  103. (0x80 & val); // treat all unicode as alphabetic
  104. }
  105. static bool isDigit( char val )
  106. {
  107. return '0' <= val && '9' >= val;
  108. }
  109. static bool isHexDigit( char val )
  110. {
  111. return ('0' <= val && '9' >= val) ||
  112. ('a' <= val && 'f' >= val) ||
  113. ('A' <= val && 'F' >= val);
  114. }
  115. static ubyte ascii2hex( char val )
  116. {
  117. if (val >= 'a' && val <= 'f')
  118. return cast(ubyte)(val - 'a' + 10);
  119. if (val >= 'A' && val <= 'F')
  120. return cast(ubyte)(val - 'A' + 10);
  121. if (val >= '0' && val <= '9')
  122. return cast(ubyte)(val - '0');
  123. error();
  124. return 0;
  125. }
  126. //////////////////////////////////////////////////////////////////////////
  127. // Data Output
  128. //////////////////////////////////////////////////////////////////////////
  129. static bool contains( const(char)[] a, const(char)[] b ) @trusted
  130. {
  131. if (a.length && b.length)
  132. {
  133. auto bend = b.ptr + b.length;
  134. auto aend = a.ptr + a.length;
  135. return a.ptr <= b.ptr && bend <= aend;
  136. }
  137. return false;
  138. }
  139. // move val to the end of the dst buffer
  140. char[] shift( const(char)[] val )
  141. {
  142. pragma(inline, false); // tame dmd inliner
  143. if ( val.length && !mute )
  144. {
  145. assert( contains( dst[0 .. len], val ) );
  146. debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
  147. if (len + val.length > dst.length)
  148. overflow();
  149. size_t v = &val[0] - &dst[0];
  150. dst[len .. len + val.length] = val[];
  151. for (size_t p = v; p < len; p++)
  152. dst[p] = dst[p + val.length];
  153. return dst[len - val.length .. len];
  154. }
  155. return null;
  156. }
  157. // remove val from dst buffer
  158. void remove( const(char)[] val )
  159. {
  160. pragma(inline, false); // tame dmd inliner
  161. if ( val.length )
  162. {
  163. assert( contains( dst[0 .. len], val ) );
  164. debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr );
  165. size_t v = &val[0] - &dst[0];
  166. assert( len >= val.length && len <= dst.length );
  167. len -= val.length;
  168. for (size_t p = v; p < len; p++)
  169. dst[p] = dst[p + val.length];
  170. }
  171. }
  172. char[] append( const(char)[] val ) return scope
  173. {
  174. pragma(inline, false); // tame dmd inliner
  175. if ( val.length && !mute )
  176. {
  177. if ( !dst.length )
  178. dst.length = minBufSize;
  179. assert( !contains( dst[0 .. len], val ) );
  180. debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
  181. if ( dst.length - len >= val.length && &dst[len] == &val[0] )
  182. {
  183. // data is already in place
  184. auto t = dst[len .. len + val.length];
  185. len += val.length;
  186. return t;
  187. }
  188. if ( dst.length - len >= val.length )
  189. {
  190. dst[len .. len + val.length] = val[];
  191. auto t = dst[len .. len + val.length];
  192. len += val.length;
  193. return t;
  194. }
  195. overflow();
  196. }
  197. return null;
  198. }
  199. void putComma(size_t n)
  200. {
  201. pragma(inline, false);
  202. if (n)
  203. put(", ");
  204. }
  205. char[] put(char c) return scope
  206. {
  207. char[1] val = c;
  208. return put(val[]);
  209. }
  210. char[] put( scope const(char)[] val ) return scope
  211. {
  212. pragma(inline, false); // tame dmd inliner
  213. if ( val.length )
  214. {
  215. if ( !contains( dst[0 .. len], val ) )
  216. return append( val );
  217. return shift( val );
  218. }
  219. return null;
  220. }
  221. void putAsHex( size_t val, int width = 0 )
  222. {
  223. import core.internal.string;
  224. UnsignedStringBuf buf = void;
  225. auto s = unsignedToTempString!16(val, buf);
  226. int slen = cast(int)s.length;
  227. if (slen < width)
  228. {
  229. foreach (i; slen .. width)
  230. put('0');
  231. }
  232. put(s);
  233. }
  234. void pad( const(char)[] val )
  235. {
  236. if ( val.length )
  237. {
  238. append( " " );
  239. put( val );
  240. }
  241. }
  242. void silent( void delegate() pure @safe dg )
  243. {
  244. debug(trace) printf( "silent+\n" );
  245. debug(trace) scope(success) printf( "silent-\n" );
  246. auto n = len; dg(); len = n;
  247. }
  248. //////////////////////////////////////////////////////////////////////////
  249. // Parsing Utility
  250. //////////////////////////////////////////////////////////////////////////
  251. @property bool empty()
  252. {
  253. return pos >= buf.length;
  254. }
  255. @property char front()
  256. {
  257. if ( pos < buf.length )
  258. return buf[pos];
  259. return char.init;
  260. }
  261. char peek( size_t n )
  262. {
  263. if ( pos + n < buf.length )
  264. return buf[pos + n];
  265. return char.init;
  266. }
  267. void test( char val )
  268. {
  269. if ( val != front )
  270. error();
  271. }
  272. void popFront()
  273. {
  274. if ( pos++ >= buf.length )
  275. error();
  276. }
  277. void popFront(int i)
  278. {
  279. while (i--)
  280. popFront();
  281. }
  282. void match( char val )
  283. {
  284. test( val );
  285. popFront();
  286. }
  287. void match( const(char)[] val )
  288. {
  289. foreach (char e; val )
  290. {
  291. test( e );
  292. popFront();
  293. }
  294. }
  295. void eat( char val )
  296. {
  297. if ( val == front )
  298. popFront();
  299. }
  300. bool isSymbolNameFront()
  301. {
  302. char val = front;
  303. if ( isDigit( val ) || val == '_' )
  304. return true;
  305. if ( val != 'Q' )
  306. return false;
  307. // check the back reference encoding after 'Q'
  308. val = peekBackref();
  309. return isDigit( val ); // identifier ref
  310. }
  311. // return the first character at the back reference
  312. char peekBackref()
  313. {
  314. assert( front == 'Q' );
  315. auto n = decodeBackref!1();
  316. if (!n || n > pos)
  317. error("invalid back reference");
  318. return buf[pos - n];
  319. }
  320. size_t decodeBackref(size_t peekAt = 0)()
  321. {
  322. enum base = 26;
  323. size_t n = 0;
  324. for (size_t p; ; p++)
  325. {
  326. char t;
  327. static if (peekAt > 0)
  328. {
  329. t = peek(peekAt + p);
  330. }
  331. else
  332. {
  333. t = front;
  334. popFront();
  335. }
  336. if (t < 'A' || t > 'Z')
  337. {
  338. if (t < 'a' || t > 'z')
  339. error("invalid back reference");
  340. n = base * n + t - 'a';
  341. return n;
  342. }
  343. n = base * n + t - 'A';
  344. }
  345. }
  346. //////////////////////////////////////////////////////////////////////////
  347. // Parsing Implementation
  348. //////////////////////////////////////////////////////////////////////////
  349. /*
  350. Number:
  351. Digit
  352. Digit Number
  353. */
  354. const(char)[] sliceNumber() return scope
  355. {
  356. debug(trace) printf( "sliceNumber+\n" );
  357. debug(trace) scope(success) printf( "sliceNumber-\n" );
  358. auto beg = pos;
  359. while ( true )
  360. {
  361. auto t = front;
  362. if (t >= '0' && t <= '9')
  363. popFront();
  364. else
  365. return buf[beg .. pos];
  366. }
  367. }
  368. size_t decodeNumber() scope
  369. {
  370. debug(trace) printf( "decodeNumber+\n" );
  371. debug(trace) scope(success) printf( "decodeNumber-\n" );
  372. return decodeNumber( sliceNumber() );
  373. }
  374. size_t decodeNumber( scope const(char)[] num ) scope
  375. {
  376. debug(trace) printf( "decodeNumber+\n" );
  377. debug(trace) scope(success) printf( "decodeNumber-\n" );
  378. size_t val = 0;
  379. foreach ( c; num )
  380. {
  381. import core.checkedint : mulu, addu;
  382. bool overflow = false;
  383. val = mulu(val, 10, overflow);
  384. val = addu(val, c - '0', overflow);
  385. if (overflow)
  386. error();
  387. }
  388. return val;
  389. }
  390. void parseReal() scope
  391. {
  392. debug(trace) printf( "parseReal+\n" );
  393. debug(trace) scope(success) printf( "parseReal-\n" );
  394. char[64] tbuf = void;
  395. size_t tlen = 0;
  396. real val = void;
  397. if ( 'I' == front )
  398. {
  399. match( "INF" );
  400. put( "real.infinity" );
  401. return;
  402. }
  403. if ( 'N' == front )
  404. {
  405. popFront();
  406. if ( 'I' == front )
  407. {
  408. match( "INF" );
  409. put( "-real.infinity" );
  410. return;
  411. }
  412. if ( 'A' == front )
  413. {
  414. match( "AN" );
  415. put( "real.nan" );
  416. return;
  417. }
  418. tbuf[tlen++] = '-';
  419. }
  420. tbuf[tlen++] = '0';
  421. tbuf[tlen++] = 'X';
  422. if ( !isHexDigit( front ) )
  423. error( "Expected hex digit" );
  424. tbuf[tlen++] = front;
  425. tbuf[tlen++] = '.';
  426. popFront();
  427. while ( isHexDigit( front ) )
  428. {
  429. tbuf[tlen++] = front;
  430. popFront();
  431. }
  432. match( 'P' );
  433. tbuf[tlen++] = 'p';
  434. if ( 'N' == front )
  435. {
  436. tbuf[tlen++] = '-';
  437. popFront();
  438. }
  439. else
  440. {
  441. tbuf[tlen++] = '+';
  442. }
  443. while ( isDigit( front ) )
  444. {
  445. tbuf[tlen++] = front;
  446. popFront();
  447. }
  448. tbuf[tlen] = 0;
  449. debug(info) printf( "got (%s)\n", tbuf.ptr );
  450. pureReprintReal( tbuf[] );
  451. debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr );
  452. put( tbuf[0 .. tlen] );
  453. }
  454. /*
  455. LName:
  456. Number Name
  457. Name:
  458. Namestart
  459. Namestart Namechars
  460. Namestart:
  461. _
  462. Alpha
  463. Namechar:
  464. Namestart
  465. Digit
  466. Namechars:
  467. Namechar
  468. Namechar Namechars
  469. */
  470. void parseLName() scope
  471. {
  472. debug(trace) printf( "parseLName+\n" );
  473. debug(trace) scope(success) printf( "parseLName-\n" );
  474. static if (__traits(hasMember, Hooks, "parseLName"))
  475. if (hooks.parseLName(this))
  476. return;
  477. if ( front == 'Q' )
  478. {
  479. // back reference to LName
  480. auto refPos = pos;
  481. popFront();
  482. size_t n = decodeBackref();
  483. if ( !n || n > refPos )
  484. error( "Invalid LName back reference" );
  485. if ( !mute )
  486. {
  487. auto savePos = pos;
  488. scope(exit) pos = savePos;
  489. pos = refPos - n;
  490. parseLName();
  491. }
  492. return;
  493. }
  494. auto n = decodeNumber();
  495. if ( n == 0 )
  496. {
  497. put( "__anonymous" );
  498. return;
  499. }
  500. if ( n > buf.length || n > buf.length - pos )
  501. error( "LName must be at least 1 character" );
  502. if ( '_' != front && !isAlpha( front ) )
  503. error( "Invalid character in LName" );
  504. foreach (char e; buf[pos + 1 .. pos + n] )
  505. {
  506. if ( '_' != e && !isAlpha( e ) && !isDigit( e ) )
  507. error( "Invalid character in LName" );
  508. }
  509. put( buf[pos .. pos + n] );
  510. pos += n;
  511. }
  512. /*
  513. Type:
  514. Shared
  515. Const
  516. Immutable
  517. Wild
  518. TypeArray
  519. TypeVector
  520. TypeStaticArray
  521. TypeAssocArray
  522. TypePointer
  523. TypeFunction
  524. TypeIdent
  525. TypeClass
  526. TypeStruct
  527. TypeEnum
  528. TypeTypedef
  529. TypeDelegate
  530. TypeNone
  531. TypeVoid
  532. TypeNoreturn
  533. TypeByte
  534. TypeUbyte
  535. TypeShort
  536. TypeUshort
  537. TypeInt
  538. TypeUint
  539. TypeLong
  540. TypeUlong
  541. TypeCent
  542. TypeUcent
  543. TypeFloat
  544. TypeDouble
  545. TypeReal
  546. TypeIfloat
  547. TypeIdouble
  548. TypeIreal
  549. TypeCfloat
  550. TypeCdouble
  551. TypeCreal
  552. TypeBool
  553. TypeChar
  554. TypeWchar
  555. TypeDchar
  556. TypeTuple
  557. Shared:
  558. O Type
  559. Const:
  560. x Type
  561. Immutable:
  562. y Type
  563. Wild:
  564. Ng Type
  565. TypeArray:
  566. A Type
  567. TypeVector:
  568. Nh Type
  569. TypeStaticArray:
  570. G Number Type
  571. TypeAssocArray:
  572. H Type Type
  573. TypePointer:
  574. P Type
  575. TypeFunction:
  576. CallConvention FuncAttrs Arguments ArgClose Type
  577. TypeIdent:
  578. I LName
  579. TypeClass:
  580. C LName
  581. TypeStruct:
  582. S LName
  583. TypeEnum:
  584. E LName
  585. TypeTypedef:
  586. T LName
  587. TypeDelegate:
  588. D TypeFunction
  589. TypeNone:
  590. n
  591. TypeVoid:
  592. v
  593. TypeNoreturn
  594. Nn
  595. TypeByte:
  596. g
  597. TypeUbyte:
  598. h
  599. TypeShort:
  600. s
  601. TypeUshort:
  602. t
  603. TypeInt:
  604. i
  605. TypeUint:
  606. k
  607. TypeLong:
  608. l
  609. TypeUlong:
  610. m
  611. TypeCent
  612. zi
  613. TypeUcent
  614. zk
  615. TypeFloat:
  616. f
  617. TypeDouble:
  618. d
  619. TypeReal:
  620. e
  621. TypeIfloat:
  622. o
  623. TypeIdouble:
  624. p
  625. TypeIreal:
  626. j
  627. TypeCfloat:
  628. q
  629. TypeCdouble:
  630. r
  631. TypeCreal:
  632. c
  633. TypeBool:
  634. b
  635. TypeChar:
  636. a
  637. TypeWchar:
  638. u
  639. TypeDchar:
  640. w
  641. TypeTuple:
  642. B Number Arguments
  643. */
  644. char[] parseType( char[] name = null ) return scope
  645. {
  646. static immutable string[23] primitives = [
  647. "char", // a
  648. "bool", // b
  649. "creal", // c
  650. "double", // d
  651. "real", // e
  652. "float", // f
  653. "byte", // g
  654. "ubyte", // h
  655. "int", // i
  656. "ireal", // j
  657. "uint", // k
  658. "long", // l
  659. "ulong", // m
  660. null, // n
  661. "ifloat", // o
  662. "idouble", // p
  663. "cfloat", // q
  664. "cdouble", // r
  665. "short", // s
  666. "ushort", // t
  667. "wchar", // u
  668. "void", // v
  669. "dchar", // w
  670. ];
  671. static if (__traits(hasMember, Hooks, "parseType"))
  672. if (auto n = hooks.parseType(this, name))
  673. return n;
  674. debug(trace) printf( "parseType+\n" );
  675. debug(trace) scope(success) printf( "parseType-\n" );
  676. auto beg = len;
  677. auto t = front;
  678. char[] parseBackrefType(scope char[] delegate() pure @safe parseDg) pure @safe
  679. {
  680. if (pos == brp)
  681. error("recursive back reference");
  682. auto refPos = pos;
  683. popFront();
  684. auto n = decodeBackref();
  685. if (n == 0 || n > pos)
  686. error("invalid back reference");
  687. if ( mute )
  688. return null;
  689. auto savePos = pos;
  690. auto saveBrp = brp;
  691. scope(success) { pos = savePos; brp = saveBrp; }
  692. pos = refPos - n;
  693. brp = refPos;
  694. auto ret = parseDg();
  695. return ret;
  696. }
  697. switch ( t )
  698. {
  699. case 'Q': // Type back reference
  700. return parseBackrefType( () => parseType( name ) );
  701. case 'O': // Shared (O Type)
  702. popFront();
  703. put( "shared(" );
  704. parseType();
  705. put( ')' );
  706. pad( name );
  707. return dst[beg .. len];
  708. case 'x': // Const (x Type)
  709. popFront();
  710. put( "const(" );
  711. parseType();
  712. put( ')' );
  713. pad( name );
  714. return dst[beg .. len];
  715. case 'y': // Immutable (y Type)
  716. popFront();
  717. put( "immutable(" );
  718. parseType();
  719. put( ')' );
  720. pad( name );
  721. return dst[beg .. len];
  722. case 'N':
  723. popFront();
  724. switch ( front )
  725. {
  726. case 'n': // Noreturn
  727. popFront();
  728. put("noreturn");
  729. return dst[beg .. len];
  730. case 'g': // Wild (Ng Type)
  731. popFront();
  732. // TODO: Anything needed here?
  733. put( "inout(" );
  734. parseType();
  735. put( ')' );
  736. return dst[beg .. len];
  737. case 'h': // TypeVector (Nh Type)
  738. popFront();
  739. put( "__vector(" );
  740. parseType();
  741. put( ')' );
  742. return dst[beg .. len];
  743. default:
  744. error();
  745. assert( 0 );
  746. }
  747. case 'A': // TypeArray (A Type)
  748. popFront();
  749. parseType();
  750. put( "[]" );
  751. pad( name );
  752. return dst[beg .. len];
  753. case 'G': // TypeStaticArray (G Number Type)
  754. popFront();
  755. auto num = sliceNumber();
  756. parseType();
  757. put( '[' );
  758. put( num );
  759. put( ']' );
  760. pad( name );
  761. return dst[beg .. len];
  762. case 'H': // TypeAssocArray (H Type Type)
  763. popFront();
  764. // skip t1
  765. auto tx = parseType();
  766. parseType();
  767. put( '[' );
  768. put( tx );
  769. put( ']' );
  770. pad( name );
  771. return dst[beg .. len];
  772. case 'P': // TypePointer (P Type)
  773. popFront();
  774. parseType();
  775. put( '*' );
  776. pad( name );
  777. return dst[beg .. len];
  778. case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
  779. return parseTypeFunction( name );
  780. case 'C': // TypeClass (C LName)
  781. case 'S': // TypeStruct (S LName)
  782. case 'E': // TypeEnum (E LName)
  783. case 'T': // TypeTypedef (T LName)
  784. popFront();
  785. parseQualifiedName();
  786. pad( name );
  787. return dst[beg .. len];
  788. case 'D': // TypeDelegate (D TypeFunction)
  789. popFront();
  790. auto modbeg = len;
  791. parseModifier();
  792. auto modend = len;
  793. if ( front == 'Q' )
  794. parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) );
  795. else
  796. parseTypeFunction( name, IsDelegate.yes );
  797. if (modend > modbeg)
  798. {
  799. // move modifiers behind the function arguments
  800. shift(dst[modend-1 .. modend]); // trailing space
  801. shift(dst[modbeg .. modend-1]);
  802. }
  803. return dst[beg .. len];
  804. case 'n': // TypeNone (n)
  805. popFront();
  806. // TODO: Anything needed here?
  807. return dst[beg .. len];
  808. case 'B': // TypeTuple (B Number Arguments)
  809. popFront();
  810. // TODO: Handle this.
  811. return dst[beg .. len];
  812. case 'Z': // Internal symbol
  813. // This 'type' is used for untyped internal symbols, i.e.:
  814. // __array
  815. // __init
  816. // __vtbl
  817. // __Class
  818. // __Interface
  819. // __ModuleInfo
  820. popFront();
  821. return dst[beg .. len];
  822. default:
  823. if (t >= 'a' && t <= 'w')
  824. {
  825. popFront();
  826. put( primitives[cast(size_t)(t - 'a')] );
  827. pad( name );
  828. return dst[beg .. len];
  829. }
  830. else if (t == 'z')
  831. {
  832. popFront();
  833. switch ( front )
  834. {
  835. case 'i':
  836. popFront();
  837. put( "cent" );
  838. pad( name );
  839. return dst[beg .. len];
  840. case 'k':
  841. popFront();
  842. put( "ucent" );
  843. pad( name );
  844. return dst[beg .. len];
  845. default:
  846. error();
  847. assert( 0 );
  848. }
  849. }
  850. error();
  851. return null;
  852. }
  853. }
  854. /*
  855. TypeFunction:
  856. CallConvention FuncAttrs Arguments ArgClose Type
  857. CallConvention:
  858. F // D
  859. U // C
  860. W // Windows
  861. R // C++
  862. FuncAttrs:
  863. FuncAttr
  864. FuncAttr FuncAttrs
  865. FuncAttr:
  866. empty
  867. FuncAttrPure
  868. FuncAttrNothrow
  869. FuncAttrProperty
  870. FuncAttrRef
  871. FuncAttrReturn
  872. FuncAttrScope
  873. FuncAttrTrusted
  874. FuncAttrSafe
  875. FuncAttrPure:
  876. Na
  877. FuncAttrNothrow:
  878. Nb
  879. FuncAttrRef:
  880. Nc
  881. FuncAttrProperty:
  882. Nd
  883. FuncAttrTrusted:
  884. Ne
  885. FuncAttrSafe:
  886. Nf
  887. FuncAttrNogc:
  888. Ni
  889. FuncAttrReturn:
  890. Nj
  891. FuncAttrScope:
  892. Nl
  893. Arguments:
  894. Argument
  895. Argument Arguments
  896. Argument:
  897. Argument2
  898. M Argument2 // scope
  899. Argument2:
  900. Type
  901. J Type // out
  902. K Type // ref
  903. L Type // lazy
  904. ArgClose
  905. X // variadic T t,...) style
  906. Y // variadic T t...) style
  907. Z // not variadic
  908. */
  909. void parseCallConvention()
  910. {
  911. // CallConvention
  912. switch ( front )
  913. {
  914. case 'F': // D
  915. popFront();
  916. break;
  917. case 'U': // C
  918. popFront();
  919. put( "extern (C) " );
  920. break;
  921. case 'W': // Windows
  922. popFront();
  923. put( "extern (Windows) " );
  924. break;
  925. case 'R': // C++
  926. popFront();
  927. put( "extern (C++) " );
  928. break;
  929. default:
  930. error();
  931. }
  932. }
  933. void parseModifier()
  934. {
  935. switch ( front )
  936. {
  937. case 'y':
  938. popFront();
  939. put( "immutable " );
  940. break;
  941. case 'O':
  942. popFront();
  943. put( "shared " );
  944. if ( front == 'x' )
  945. goto case 'x';
  946. if ( front == 'N' )
  947. goto case 'N';
  948. break;
  949. case 'N':
  950. if ( peek( 1 ) != 'g' )
  951. break;
  952. popFront();
  953. popFront();
  954. put( "inout " );
  955. if ( front == 'x' )
  956. goto case 'x';
  957. break;
  958. case 'x':
  959. popFront();
  960. put( "const " );
  961. break;
  962. default: break;
  963. }
  964. }
  965. void parseFuncAttr()
  966. {
  967. // FuncAttrs
  968. breakFuncAttrs:
  969. while ('N' == front)
  970. {
  971. popFront();
  972. switch ( front )
  973. {
  974. case 'a': // FuncAttrPure
  975. popFront();
  976. put( "pure " );
  977. continue;
  978. case 'b': // FuncAttrNoThrow
  979. popFront();
  980. put( "nothrow " );
  981. continue;
  982. case 'c': // FuncAttrRef
  983. popFront();
  984. put( "ref " );
  985. continue;
  986. case 'd': // FuncAttrProperty
  987. popFront();
  988. put( "@property " );
  989. continue;
  990. case 'e': // FuncAttrTrusted
  991. popFront();
  992. put( "@trusted " );
  993. continue;
  994. case 'f': // FuncAttrSafe
  995. popFront();
  996. put( "@safe " );
  997. continue;
  998. case 'g':
  999. case 'h':
  1000. case 'k':
  1001. case 'n':
  1002. // NOTE: The inout parameter type is represented as "Ng".
  1003. // The vector parameter type is represented as "Nh".
  1004. // The return parameter type is represented as "Nk".
  1005. // The noreturn parameter type is represented as "Nn".
  1006. // These make it look like a FuncAttr, but infact
  1007. // if we see these, then we know we're really in
  1008. // the parameter list. Rewind and break.
  1009. pos--;
  1010. break breakFuncAttrs;
  1011. case 'i': // FuncAttrNogc
  1012. popFront();
  1013. put( "@nogc " );
  1014. continue;
  1015. case 'j': // FuncAttrReturn
  1016. popFront();
  1017. put( "return " );
  1018. continue;
  1019. case 'l': // FuncAttrScope
  1020. popFront();
  1021. put( "scope " );
  1022. continue;
  1023. case 'm': // FuncAttrLive
  1024. popFront();
  1025. put( "@live " );
  1026. continue;
  1027. default:
  1028. error();
  1029. }
  1030. }
  1031. }
  1032. void parseFuncArguments() scope
  1033. {
  1034. // Arguments
  1035. for ( size_t n = 0; true; n++ )
  1036. {
  1037. debug(info) printf( "tok (%c)\n", front );
  1038. switch ( front )
  1039. {
  1040. case 'X': // ArgClose (variadic T t...) style)
  1041. popFront();
  1042. put( "..." );
  1043. return;
  1044. case 'Y': // ArgClose (variadic T t,...) style)
  1045. popFront();
  1046. put( ", ..." );
  1047. return;
  1048. case 'Z': // ArgClose (not variadic)
  1049. popFront();
  1050. return;
  1051. default:
  1052. break;
  1053. }
  1054. putComma(n);
  1055. /* Do special return, scope, ref, out combinations
  1056. */
  1057. int npops;
  1058. if ( 'M' == front && peek(1) == 'N' && peek(2) == 'k')
  1059. {
  1060. const c3 = peek(3);
  1061. if (c3 == 'J')
  1062. {
  1063. put("scope return out "); // MNkJ
  1064. npops = 4;
  1065. }
  1066. else if (c3 == 'K')
  1067. {
  1068. put("scope return ref "); // MNkK
  1069. npops = 4;
  1070. }
  1071. }
  1072. else if ('N' == front && peek(1) == 'k')
  1073. {
  1074. const c2 = peek(2);
  1075. if (c2 == 'J')
  1076. {
  1077. put("return out "); // NkJ
  1078. npops = 3;
  1079. }
  1080. else if (c2 == 'K')
  1081. {
  1082. put("return ref "); // NkK
  1083. npops = 3;
  1084. }
  1085. else if (c2 == 'M')
  1086. {
  1087. const c3 = peek(3);
  1088. if (c3 == 'J')
  1089. {
  1090. put("return scope out "); // NkMJ
  1091. npops = 4;
  1092. }
  1093. else if (c3 == 'K')
  1094. {
  1095. put("return scope ref "); // NkMK
  1096. npops = 4;
  1097. }
  1098. else
  1099. {
  1100. put("return scope "); // NkM
  1101. npops = 3;
  1102. }
  1103. }
  1104. }
  1105. popFront(npops);
  1106. if ( 'M' == front )
  1107. {
  1108. popFront();
  1109. put( "scope " );
  1110. }
  1111. if ( 'N' == front )
  1112. {
  1113. popFront();
  1114. if ( 'k' == front ) // Return (Nk Parameter2)
  1115. {
  1116. popFront();
  1117. put( "return " );
  1118. }
  1119. else
  1120. pos--;
  1121. }
  1122. switch ( front )
  1123. {
  1124. case 'I': // in (I Type)
  1125. popFront();
  1126. put("in ");
  1127. if (front == 'K')
  1128. goto case;
  1129. parseType();
  1130. continue;
  1131. case 'K': // ref (K Type)
  1132. popFront();
  1133. put( "ref " );
  1134. parseType();
  1135. continue;
  1136. case 'J': // out (J Type)
  1137. popFront();
  1138. put( "out " );
  1139. parseType();
  1140. continue;
  1141. case 'L': // lazy (L Type)
  1142. popFront();
  1143. put( "lazy " );
  1144. parseType();
  1145. continue;
  1146. default:
  1147. parseType();
  1148. }
  1149. }
  1150. }
  1151. enum IsDelegate { no, yes }
  1152. /*
  1153. TypeFunction:
  1154. CallConvention FuncAttrs Arguments ArgClose Type
  1155. */
  1156. char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
  1157. {
  1158. debug(trace) printf( "parseTypeFunction+\n" );
  1159. debug(trace) scope(success) printf( "parseTypeFunction-\n" );
  1160. auto beg = len;
  1161. parseCallConvention();
  1162. auto attrbeg = len;
  1163. parseFuncAttr();
  1164. auto argbeg = len;
  1165. put( '(' );
  1166. parseFuncArguments();
  1167. put( ')' );
  1168. if (attrbeg < argbeg)
  1169. {
  1170. // move function attributes behind arguments
  1171. shift( dst[argbeg - 1 .. argbeg] ); // trailing space
  1172. shift( dst[attrbeg .. argbeg - 1] ); // attributes
  1173. argbeg = attrbeg;
  1174. }
  1175. auto retbeg = len;
  1176. parseType();
  1177. put( ' ' );
  1178. // append name/delegate/function
  1179. if ( name.length )
  1180. {
  1181. if ( !contains( dst[0 .. len], name ) )
  1182. put( name );
  1183. else if ( shift( name ).ptr != name.ptr )
  1184. {
  1185. argbeg -= name.length;
  1186. retbeg -= name.length;
  1187. }
  1188. }
  1189. else if ( IsDelegate.yes == isdg )
  1190. put( "delegate" );
  1191. else
  1192. put( "function" );
  1193. // move arguments and attributes behind name
  1194. shift( dst[argbeg .. retbeg] );
  1195. return dst[beg..len];
  1196. }
  1197. static bool isCallConvention( char ch )
  1198. {
  1199. switch ( ch )
  1200. {
  1201. case 'F', 'U', 'V', 'W', 'R':
  1202. return true;
  1203. default:
  1204. return false;
  1205. }
  1206. }
  1207. /*
  1208. Value:
  1209. n
  1210. Number
  1211. i Number
  1212. N Number
  1213. e HexFloat
  1214. c HexFloat c HexFloat
  1215. A Number Value...
  1216. HexFloat:
  1217. NAN
  1218. INF
  1219. NINF
  1220. N HexDigits P Exponent
  1221. HexDigits P Exponent
  1222. Exponent:
  1223. N Number
  1224. Number
  1225. HexDigits:
  1226. HexDigit
  1227. HexDigit HexDigits
  1228. HexDigit:
  1229. Digit
  1230. A
  1231. B
  1232. C
  1233. D
  1234. E
  1235. F
  1236. */
  1237. void parseValue(scope char[] name = null, char type = '\0' ) scope
  1238. {
  1239. debug(trace) printf( "parseValue+\n" );
  1240. debug(trace) scope(success) printf( "parseValue-\n" );
  1241. // printf( "*** %c\n", front );
  1242. switch ( front )
  1243. {
  1244. case 'n':
  1245. popFront();
  1246. put( "null" );
  1247. return;
  1248. case 'i':
  1249. popFront();
  1250. if ( '0' > front || '9' < front )
  1251. error( "Number expected" );
  1252. goto case;
  1253. case '0': .. case '9':
  1254. parseIntegerValue( name, type );
  1255. return;
  1256. case 'N':
  1257. popFront();
  1258. put( '-' );
  1259. parseIntegerValue( name, type );
  1260. return;
  1261. case 'e':
  1262. popFront();
  1263. parseReal();
  1264. return;
  1265. case 'c':
  1266. popFront();
  1267. parseReal();
  1268. put( '+' );
  1269. match( 'c' );
  1270. parseReal();
  1271. put( 'i' );
  1272. return;
  1273. case 'a': case 'w': case 'd':
  1274. char t = front;
  1275. popFront();
  1276. auto n = decodeNumber();
  1277. match( '_' );
  1278. put( '"' );
  1279. foreach (i; 0..n)
  1280. {
  1281. auto a = ascii2hex( front ); popFront();
  1282. auto b = ascii2hex( front ); popFront();
  1283. auto v = cast(char)((a << 4) | b);
  1284. if (' ' <= v && v <= '~') // ASCII printable
  1285. {
  1286. put(v);
  1287. }
  1288. else
  1289. {
  1290. put("\\x");
  1291. putAsHex(v, 2);
  1292. }
  1293. }
  1294. put( '"' );
  1295. if ( 'a' != t )
  1296. put(t);
  1297. return;
  1298. case 'A':
  1299. // NOTE: This is kind of a hack. An associative array literal
  1300. // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type
  1301. // is "Hii" and the value is "A2i1i2i3i4". Thus the only
  1302. // way to determine that this is an AA value rather than an
  1303. // array value is for the caller to supply the type char.
  1304. // Hopefully, this will change so that the value is
  1305. // "H2i1i2i3i4", rendering this unnecesary.
  1306. if ( 'H' == type )
  1307. goto LassocArray;
  1308. // A Number Value...
  1309. // An array literal. Value is repeated Number times.
  1310. popFront();
  1311. put( '[' );
  1312. auto n = decodeNumber();
  1313. foreach ( i; 0 .. n )
  1314. {
  1315. putComma(i);
  1316. parseValue();
  1317. }
  1318. put( ']' );
  1319. return;
  1320. case 'H':
  1321. LassocArray:
  1322. // H Number Value...
  1323. // An associative array literal. Value is repeated 2*Number times.
  1324. popFront();
  1325. put( '[' );
  1326. auto n = decodeNumber();
  1327. foreach ( i; 0 .. n )
  1328. {
  1329. putComma(i);
  1330. parseValue();
  1331. put(':');
  1332. parseValue();
  1333. }
  1334. put( ']' );
  1335. return;
  1336. case 'S':
  1337. // S Number Value...
  1338. // A struct literal. Value is repeated Number times.
  1339. popFront();
  1340. if ( name.length )
  1341. put( name );
  1342. put( '(' );
  1343. auto n = decodeNumber();
  1344. foreach ( i; 0 .. n )
  1345. {
  1346. putComma(i);
  1347. parseValue();
  1348. }
  1349. put( ')' );
  1350. return;
  1351. case 'f':
  1352. // f MangledName
  1353. // A function literal symbol
  1354. popFront();
  1355. parseMangledName(false, 1);
  1356. return;
  1357. default:
  1358. error();
  1359. }
  1360. }
  1361. void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope
  1362. {
  1363. debug(trace) printf( "parseIntegerValue+\n" );
  1364. debug(trace) scope(success) printf( "parseIntegerValue-\n" );
  1365. switch ( type )
  1366. {
  1367. case 'a': // char
  1368. case 'u': // wchar
  1369. case 'w': // dchar
  1370. {
  1371. auto val = sliceNumber();
  1372. auto num = decodeNumber( val );
  1373. switch ( num )
  1374. {
  1375. case '\'':
  1376. put( "'\\''" );
  1377. return;
  1378. // \", \?
  1379. case '\\':
  1380. put( "'\\\\'" );
  1381. return;
  1382. case '\a':
  1383. put( "'\\a'" );
  1384. return;
  1385. case '\b':
  1386. put( "'\\b'" );
  1387. return;
  1388. case '\f':
  1389. put( "'\\f'" );
  1390. return;
  1391. case '\n':
  1392. put( "'\\n'" );
  1393. return;
  1394. case '\r':
  1395. put( "'\\r'" );
  1396. return;
  1397. case '\t':
  1398. put( "'\\t'" );
  1399. return;
  1400. case '\v':
  1401. put( "'\\v'" );
  1402. return;
  1403. default:
  1404. switch ( type )
  1405. {
  1406. case 'a':
  1407. if ( num >= 0x20 && num < 0x7F )
  1408. {
  1409. put( '\'' );
  1410. put( cast(char)num );
  1411. put( '\'' );
  1412. return;
  1413. }
  1414. put( "\\x" );
  1415. putAsHex( num, 2 );
  1416. return;
  1417. case 'u':
  1418. put( "'\\u" );
  1419. putAsHex( num, 4 );
  1420. put( '\'' );
  1421. return;
  1422. case 'w':
  1423. put( "'\\U" );
  1424. putAsHex( num, 8 );
  1425. put( '\'' );
  1426. return;
  1427. default:
  1428. assert( 0 );
  1429. }
  1430. }
  1431. }
  1432. case 'b': // bool
  1433. put( decodeNumber() ? "true" : "false" );
  1434. return;
  1435. case 'h', 't', 'k': // ubyte, ushort, uint
  1436. put( sliceNumber() );
  1437. put( 'u' );
  1438. return;
  1439. case 'l': // long
  1440. put( sliceNumber() );
  1441. put( 'L' );
  1442. return;
  1443. case 'm': // ulong
  1444. put( sliceNumber() );
  1445. put( "uL" );
  1446. return;
  1447. default:
  1448. put( sliceNumber() );
  1449. return;
  1450. }
  1451. }
  1452. /*
  1453. TemplateArgs:
  1454. TemplateArg
  1455. TemplateArg TemplateArgs
  1456. TemplateArg:
  1457. TemplateArgX
  1458. H TemplateArgX
  1459. TemplateArgX:
  1460. T Type
  1461. V Type Value
  1462. S Number_opt QualifiedName
  1463. X ExternallyMangledName
  1464. */
  1465. void parseTemplateArgs() scope
  1466. {
  1467. debug(trace) printf( "parseTemplateArgs+\n" );
  1468. debug(trace) scope(success) printf( "parseTemplateArgs-\n" );
  1469. L_nextArg:
  1470. for ( size_t n = 0; true; n++ )
  1471. {
  1472. if ( front == 'H' )
  1473. popFront();
  1474. switch ( front )
  1475. {
  1476. case 'T':
  1477. popFront();
  1478. putComma(n);
  1479. parseType();
  1480. continue;
  1481. case 'V':
  1482. popFront();
  1483. putComma(n);
  1484. // NOTE: In the few instances where the type is actually
  1485. // desired in the output it should precede the value
  1486. // generated by parseValue, so it is safe to simply
  1487. // decrement len and let put/append do its thing.
  1488. char t = front; // peek at type for parseValue
  1489. if ( t == 'Q' )
  1490. t = peekBackref();
  1491. char[] name; silent( delegate void() { name = parseType(); } );
  1492. parseValue( name, t );
  1493. continue;
  1494. case 'S':
  1495. popFront();
  1496. putComma(n);
  1497. if ( mayBeMangledNameArg() )
  1498. {
  1499. auto l = len;
  1500. auto p = pos;
  1501. auto b = brp;
  1502. try
  1503. {
  1504. debug(trace) printf( "may be mangled name arg\n" );
  1505. parseMangledNameArg();
  1506. continue;
  1507. }
  1508. catch ( ParseException e )
  1509. {
  1510. len = l;
  1511. pos = p;
  1512. brp = b;
  1513. debug(trace) printf( "not a mangled name arg\n" );
  1514. }
  1515. }
  1516. if ( isDigit( front ) && isDigit( peek( 1 ) ) )
  1517. {
  1518. // ambiguity: length followed by qualified name (starting with number)
  1519. // try all possible pairs of numbers
  1520. auto qlen = decodeNumber() / 10; // last digit needed for QualifiedName
  1521. pos--;
  1522. auto l = len;
  1523. auto p = pos;
  1524. auto b = brp;
  1525. while ( qlen > 0 )
  1526. {
  1527. try
  1528. {
  1529. parseQualifiedName();
  1530. if ( pos == p + qlen )
  1531. continue L_nextArg;
  1532. }
  1533. catch ( ParseException e )
  1534. {
  1535. }
  1536. qlen /= 10; // retry with one digit less
  1537. pos = --p;
  1538. len = l;
  1539. brp = b;
  1540. }
  1541. }
  1542. parseQualifiedName();
  1543. continue;
  1544. case 'X':
  1545. popFront();
  1546. putComma(n);
  1547. parseLName();
  1548. continue;
  1549. default:
  1550. return;
  1551. }
  1552. }
  1553. }
  1554. bool mayBeMangledNameArg()
  1555. {
  1556. debug(trace) printf( "mayBeMangledNameArg+\n" );
  1557. debug(trace) scope(success) printf( "mayBeMangledNameArg-\n" );
  1558. auto p = pos;
  1559. scope(exit) pos = p;
  1560. if ( isDigit( buf[pos] ) )
  1561. {
  1562. auto n = decodeNumber();
  1563. return n >= 4 &&
  1564. pos < buf.length && '_' == buf[pos++] &&
  1565. pos < buf.length && 'D' == buf[pos++] &&
  1566. isDigit( buf[pos] );
  1567. }
  1568. else
  1569. {
  1570. return pos < buf.length && '_' == buf[pos++] &&
  1571. pos < buf.length && 'D' == buf[pos++] &&
  1572. isSymbolNameFront();
  1573. }
  1574. }
  1575. void parseMangledNameArg()
  1576. {
  1577. debug(trace) printf( "parseMangledNameArg+\n" );
  1578. debug(trace) scope(success) printf( "parseMangledNameArg-\n" );
  1579. size_t n = 0;
  1580. if ( isDigit( front ) )
  1581. n = decodeNumber();
  1582. parseMangledName( false, n );
  1583. }
  1584. /*
  1585. TemplateInstanceName:
  1586. Number __T LName TemplateArgs Z
  1587. */
  1588. void parseTemplateInstanceName(bool hasNumber) scope
  1589. {
  1590. debug(trace) printf( "parseTemplateInstanceName+\n" );
  1591. debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" );
  1592. auto sav = pos;
  1593. auto saveBrp = brp;
  1594. scope(failure)
  1595. {
  1596. pos = sav;
  1597. brp = saveBrp;
  1598. }
  1599. auto n = hasNumber ? decodeNumber() : 0;
  1600. auto beg = pos;
  1601. match( "__T" );
  1602. parseLName();
  1603. put( "!(" );
  1604. parseTemplateArgs();
  1605. match( 'Z' );
  1606. if ( hasNumber && pos - beg != n )
  1607. error( "Template name length mismatch" );
  1608. put( ')' );
  1609. }
  1610. bool mayBeTemplateInstanceName() scope
  1611. {
  1612. debug(trace) printf( "mayBeTemplateInstanceName+\n" );
  1613. debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" );
  1614. auto p = pos;
  1615. scope(exit) pos = p;
  1616. auto n = decodeNumber();
  1617. return n >= 5 &&
  1618. pos < buf.length && '_' == buf[pos++] &&
  1619. pos < buf.length && '_' == buf[pos++] &&
  1620. pos < buf.length && 'T' == buf[pos++];
  1621. }
  1622. /*
  1623. SymbolName:
  1624. LName
  1625. TemplateInstanceName
  1626. */
  1627. void parseSymbolName() scope
  1628. {
  1629. debug(trace) printf( "parseSymbolName+\n" );
  1630. debug(trace) scope(success) printf( "parseSymbolName-\n" );
  1631. // LName -> Number
  1632. // TemplateInstanceName -> Number "__T"
  1633. switch ( front )
  1634. {
  1635. case '_':
  1636. // no length encoding for templates for new mangling
  1637. parseTemplateInstanceName(false);
  1638. return;
  1639. case '0': .. case '9':
  1640. if ( mayBeTemplateInstanceName() )
  1641. {
  1642. auto t = len;
  1643. try
  1644. {
  1645. debug(trace) printf( "may be template instance name\n" );
  1646. parseTemplateInstanceName(true);
  1647. return;
  1648. }
  1649. catch ( ParseException e )
  1650. {
  1651. debug(trace) printf( "not a template instance name\n" );
  1652. len = t;
  1653. }
  1654. }
  1655. goto case;
  1656. case 'Q':
  1657. parseLName();
  1658. return;
  1659. default:
  1660. error();
  1661. }
  1662. }
  1663. // parse optional function arguments as part of a symbol name, i.e without return type
  1664. // if keepAttr, the calling convention and function attributes are not discarded, but returned
  1665. char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope
  1666. {
  1667. // try to demangle a function, in case we are pointing to some function local
  1668. auto prevpos = pos;
  1669. auto prevlen = len;
  1670. auto prevbrp = brp;
  1671. char[] attr;
  1672. try
  1673. {
  1674. if ( 'M' == front )
  1675. {
  1676. // do not emit "needs this"
  1677. popFront();
  1678. parseModifier();
  1679. }
  1680. if ( isCallConvention( front ) )
  1681. {
  1682. // we don't want calling convention and attributes in the qualified name
  1683. parseCallConvention();
  1684. parseFuncAttr();
  1685. if ( keepAttr )
  1686. {
  1687. attr = dst[prevlen .. len];
  1688. }
  1689. else
  1690. {
  1691. len = prevlen;
  1692. }
  1693. put( '(' );
  1694. parseFuncArguments();
  1695. put( ')' );
  1696. }
  1697. }
  1698. catch ( ParseException )
  1699. {
  1700. // not part of a qualified name, so back up
  1701. pos = prevpos;
  1702. len = prevlen;
  1703. brp = prevbrp;
  1704. attr = null;
  1705. }
  1706. return attr;
  1707. }
  1708. /*
  1709. QualifiedName:
  1710. SymbolName
  1711. SymbolName QualifiedName
  1712. */
  1713. char[] parseQualifiedName() return scope
  1714. {
  1715. debug(trace) printf( "parseQualifiedName+\n" );
  1716. debug(trace) scope(success) printf( "parseQualifiedName-\n" );
  1717. size_t beg = len;
  1718. size_t n = 0;
  1719. do
  1720. {
  1721. if ( n++ )
  1722. put( '.' );
  1723. parseSymbolName();
  1724. parseFunctionTypeNoReturn();
  1725. } while ( isSymbolNameFront() );
  1726. return dst[beg .. len];
  1727. }
  1728. /*
  1729. MangledName:
  1730. _D QualifiedName Type
  1731. _D QualifiedName M Type
  1732. */
  1733. void parseMangledName( bool displayType, size_t n = 0 ) scope
  1734. {
  1735. debug(trace) printf( "parseMangledName+\n" );
  1736. debug(trace) scope(success) printf( "parseMangledName-\n" );
  1737. char[] name = null;
  1738. auto end = pos + n;
  1739. eat( '_' );
  1740. match( 'D' );
  1741. do
  1742. {
  1743. size_t beg = len;
  1744. size_t nameEnd = len;
  1745. char[] attr;
  1746. do
  1747. {
  1748. if ( attr )
  1749. remove( attr ); // dump attributes of parent symbols
  1750. if ( beg != len )
  1751. put( '.' );
  1752. parseSymbolName();
  1753. nameEnd = len;
  1754. attr = parseFunctionTypeNoReturn( displayType );
  1755. } while ( isSymbolNameFront() );
  1756. if ( displayType )
  1757. {
  1758. attr = shift( attr );
  1759. nameEnd = len - attr.length; // name includes function arguments
  1760. }
  1761. name = dst[beg .. nameEnd];
  1762. debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr );
  1763. if ( 'M' == front )
  1764. popFront(); // has 'this' pointer
  1765. auto lastlen = len;
  1766. auto type = parseType();
  1767. if ( displayType )
  1768. {
  1769. if ( type.length )
  1770. put( ' ' );
  1771. // sort (name,attr,type) -> (attr,type,name)
  1772. shift( name );
  1773. }
  1774. else
  1775. {
  1776. // remove type
  1777. assert( attr.length == 0 );
  1778. len = lastlen;
  1779. }
  1780. if ( pos >= buf.length || (n != 0 && pos >= end) )
  1781. return;
  1782. switch ( front )
  1783. {
  1784. case 'T': // terminators when used as template alias parameter
  1785. case 'V':
  1786. case 'S':
  1787. case 'Z':
  1788. return;
  1789. default:
  1790. }
  1791. put( '.' );
  1792. } while ( true );
  1793. }
  1794. void parseMangledName()
  1795. {
  1796. parseMangledName( AddType.yes == addType );
  1797. }
  1798. char[] copyInput() return scope
  1799. {
  1800. if (dst.length < buf.length)
  1801. dst.length = buf.length;
  1802. char[] r = dst[0 .. buf.length];
  1803. r[] = buf[];
  1804. return r;
  1805. }
  1806. char[] doDemangle(alias FUNC)() return scope
  1807. {
  1808. while ( true )
  1809. {
  1810. try
  1811. {
  1812. debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
  1813. FUNC();
  1814. return dst[0 .. len];
  1815. }
  1816. catch ( OverflowException e )
  1817. {
  1818. debug(trace) printf( "overflow... restarting\n" );
  1819. auto a = minBufSize;
  1820. auto b = 2 * dst.length;
  1821. auto newsz = a < b ? b : a;
  1822. debug(info) printf( "growing dst to %lu bytes\n", newsz );
  1823. dst.length = newsz;
  1824. pos = len = brp = 0;
  1825. continue;
  1826. }
  1827. catch ( ParseException e )
  1828. {
  1829. debug(info)
  1830. {
  1831. auto msg = e.toString();
  1832. printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
  1833. }
  1834. return copyInput();
  1835. }
  1836. catch ( Exception e )
  1837. {
  1838. assert( false ); // no other exceptions thrown
  1839. }
  1840. }
  1841. }
  1842. char[] demangleName() nothrow
  1843. {
  1844. return doDemangle!parseMangledName();
  1845. }
  1846. char[] demangleType() nothrow
  1847. {
  1848. return doDemangle!parseType();
  1849. }
  1850. }
  1851. /**
  1852. * Demangles D mangled names. If it is not a D mangled name, it returns its
  1853. * argument name.
  1854. *
  1855. * Params:
  1856. * buf = The string to demangle.
  1857. * dst = An optional destination buffer.
  1858. *
  1859. * Returns:
  1860. * The demangled name or the original string if the name is not a mangled D
  1861. * name.
  1862. */
  1863. char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe
  1864. {
  1865. auto d = Demangle!()(buf, dst);
  1866. // fast path (avoiding throwing & catching exception) for obvious
  1867. // non-D mangled names
  1868. if (buf.length < 2 || !(buf[0] == 'D' || buf[0..2] == "_D"))
  1869. return d.copyInput();
  1870. return d.demangleName();
  1871. }
  1872. /**
  1873. * Demangles a D mangled type.
  1874. *
  1875. * Params:
  1876. * buf = The string to demangle.
  1877. * dst = An optional destination buffer.
  1878. *
  1879. * Returns:
  1880. * The demangled type name or the original string if the name is not a
  1881. * mangled D type.
  1882. */
  1883. char[] demangleType( const(char)[] buf, char[] dst = null ) nothrow pure @safe
  1884. {
  1885. auto d = Demangle!()(buf, dst);
  1886. return d.demangleType();
  1887. }
  1888. /**
  1889. * reencode a mangled symbol name that might include duplicate occurrences
  1890. * of the same identifier by replacing all but the first occurence with
  1891. * a back reference.
  1892. *
  1893. * Params:
  1894. * mangled = The mangled string representing the type
  1895. *
  1896. * Returns:
  1897. * The mangled name with deduplicated identifiers
  1898. */
  1899. char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
  1900. {
  1901. static struct PrependHooks
  1902. {
  1903. size_t lastpos;
  1904. char[] result;
  1905. size_t[const(char)[]] idpos; // identifier positions
  1906. static struct Replacement
  1907. {
  1908. size_t pos; // postion in original mangled string
  1909. size_t respos; // postion in result string
  1910. }
  1911. Replacement [] replacements;
  1912. pure @safe:
  1913. size_t positionInResult(size_t pos) scope
  1914. {
  1915. foreach_reverse (r; replacements)
  1916. if (pos >= r.pos)
  1917. return r.respos + pos - r.pos;
  1918. return pos;
  1919. }
  1920. alias Remangle = Demangle!(PrependHooks);
  1921. void flushPosition(ref Remangle d) scope
  1922. {
  1923. if (lastpos < d.pos)
  1924. {
  1925. result ~= d.buf[lastpos .. d.pos];
  1926. }
  1927. else if (lastpos > d.pos)
  1928. {
  1929. // roll back to earlier position
  1930. while (replacements.length > 0 && replacements[$-1].pos > d.pos)
  1931. replacements = replacements[0 .. $-1];
  1932. if (replacements.length > 0)
  1933. result.length = replacements[$-1].respos + d.pos - replacements[$-1].pos;
  1934. else
  1935. result.length = d.pos;
  1936. }
  1937. }
  1938. bool parseLName(scope ref Remangle d) scope
  1939. {
  1940. flushPosition(d);
  1941. auto reslen = result.length;
  1942. auto refpos = d.pos;
  1943. if (d.front == 'Q')
  1944. {
  1945. size_t npos;
  1946. {
  1947. scope(exit) result.length = reslen; // remove all intermediate additions
  1948. // only support identifier back references
  1949. d.popFront();
  1950. size_t n = d.decodeBackref();
  1951. if (!n || n > refpos)
  1952. d.error("invalid back reference");
  1953. auto savepos = d.pos;
  1954. scope(exit) d.pos = savepos;
  1955. size_t srcpos = refpos - n;
  1956. auto idlen = d.decodeNumber();
  1957. if (d.pos + idlen > d.buf.length)
  1958. d.error("invalid back reference");
  1959. auto id = d.buf[d.pos .. d.pos + idlen];
  1960. auto pid = id in idpos;
  1961. if (!pid)
  1962. d.error("invalid back reference");
  1963. npos = positionInResult(*pid);
  1964. }
  1965. encodeBackref(reslen - npos);
  1966. const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
  1967. replacements ~= Replacement(pos, result.length);
  1968. }
  1969. else
  1970. {
  1971. auto n = d.decodeNumber();
  1972. if (!n || n > d.buf.length || n > d.buf.length - d.pos)
  1973. d.error("LName too shot or too long");
  1974. auto id = d.buf[d.pos .. d.pos + n];
  1975. d.pos += n;
  1976. if (auto pid = id in idpos)
  1977. {
  1978. size_t npos = positionInResult(*pid);
  1979. result.length = reslen;
  1980. encodeBackref(reslen - npos);
  1981. const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
  1982. replacements ~= Replacement(pos, result.length);
  1983. }
  1984. else
  1985. {
  1986. idpos[id] = refpos;
  1987. result ~= d.buf[refpos .. d.pos];
  1988. }
  1989. }
  1990. lastpos = d.pos;
  1991. return true;
  1992. }
  1993. char[] parseType( ref Remangle d, char[] name = null ) return scope
  1994. {
  1995. if (d.front != 'Q')
  1996. return null;
  1997. flushPosition(d);
  1998. auto refPos = d.pos;
  1999. d.popFront();
  2000. auto n = d.decodeBackref();
  2001. if (n == 0 || n > refPos)
  2002. d.error("invalid back reference");
  2003. size_t npos = positionInResult(refPos - n);
  2004. size_t reslen = result.length;
  2005. encodeBackref(reslen - npos);
  2006. lastpos = d.pos;
  2007. return result[reslen .. $]; // anything but null
  2008. }
  2009. void encodeBackref(size_t relpos) scope
  2010. {
  2011. result ~= 'Q';
  2012. enum base = 26;
  2013. size_t div = 1;
  2014. while (relpos >= div * base)
  2015. div *= base;
  2016. while (div >= base)
  2017. {
  2018. auto dig = (relpos / div);
  2019. result ~= cast(char)('A' + dig);
  2020. relpos -= dig * div;
  2021. div /= base;
  2022. }
  2023. result ~= cast(char)('a' + relpos);
  2024. }
  2025. }
  2026. auto d = Demangle!(PrependHooks)(mangled, null);
  2027. d.hooks = PrependHooks();
  2028. d.mute = true; // no demangled output
  2029. try
  2030. {
  2031. d.parseMangledName();
  2032. if (d.hooks.lastpos < d.pos)
  2033. d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
  2034. return d.hooks.result;
  2035. }
  2036. catch (Exception)
  2037. {
  2038. // overflow exception cannot occur
  2039. return mangled.dup;
  2040. }
  2041. }
  2042. /**
  2043. * Mangles a D symbol.
  2044. *
  2045. * Params:
  2046. * T = The type of the symbol.
  2047. * fqn = The fully qualified name of the symbol.
  2048. * dst = An optional destination buffer.
  2049. *
  2050. * Returns:
  2051. * The mangled name for a symbols of type T and the given fully
  2052. * qualified name.
  2053. */
  2054. char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow
  2055. {
  2056. import core.internal.string : numDigits, unsignedToTempString;
  2057. static struct DotSplitter
  2058. {
  2059. @safe pure nothrow:
  2060. const(char)[] s;
  2061. @property bool empty() const { return !s.length; }
  2062. @property const(char)[] front() const return
  2063. {
  2064. immutable i = indexOfDot();
  2065. return i == -1 ? s[0 .. $] : s[0 .. i];
  2066. }
  2067. void popFront() scope
  2068. {
  2069. immutable i = indexOfDot();
  2070. s = i == -1 ? s[$ .. $] : s[i+1 .. $];
  2071. }
  2072. private ptrdiff_t indexOfDot() const scope
  2073. {
  2074. foreach (i, c; s) if (c == '.') return i;
  2075. return -1;
  2076. }
  2077. }
  2078. size_t len = "_D".length;
  2079. foreach (comp; DotSplitter(fqn))
  2080. len += numDigits(comp.length) + comp.length;
  2081. len += T.mangleof.length;
  2082. if (dst.length < len) dst.length = len;
  2083. size_t i = "_D".length;
  2084. dst[0 .. i] = "_D";
  2085. foreach (comp; DotSplitter(fqn))
  2086. {
  2087. const ndigits = numDigits(comp.length);
  2088. unsignedToTempString(comp.length, dst[i .. i + ndigits]);
  2089. i += ndigits;
  2090. dst[i .. i + comp.length] = comp[];
  2091. i += comp.length;
  2092. }
  2093. dst[i .. i + T.mangleof.length] = T.mangleof[];
  2094. i += T.mangleof.length;
  2095. static if (hasTypeBackRef)
  2096. return reencodeMangled(dst[0 .. i]);
  2097. else
  2098. return dst[0 .. i];
  2099. }
  2100. ///
  2101. @safe pure nothrow unittest
  2102. {
  2103. assert(mangle!int("a.b") == "_D1a1bi");
  2104. assert(mangle!(char[])("test.foo") == "_D4test3fooAa");
  2105. assert(mangle!(int function(int))("a.b") == "_D1a1bPFiZi");
  2106. }
  2107. @safe pure nothrow unittest
  2108. {
  2109. static assert(mangle!int("a.b") == "_D1a1bi");
  2110. auto buf = new char[](10);
  2111. buf = mangle!int("a.b", buf);
  2112. assert(buf == "_D1a1bi");
  2113. buf = mangle!(char[])("test.foo", buf);
  2114. assert(buf == "_D4test3fooAa");
  2115. buf = mangle!(real delegate(int))("modµ.dg");
  2116. assert(buf == "_D5modµ2dgDFiZe", buf);
  2117. }
  2118. /**
  2119. * Mangles a D function.
  2120. *
  2121. * Params:
  2122. * T = function pointer type.
  2123. * fqn = The fully qualified name of the symbol.
  2124. * dst = An optional destination buffer.
  2125. *
  2126. * Returns:
  2127. * The mangled name for a function with function pointer type T and
  2128. * the given fully qualified name.
  2129. */
  2130. char[] mangleFunc(T:FT*, FT)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow if (is(FT == function))
  2131. {
  2132. static if (isExternD!FT)
  2133. {
  2134. return mangle!FT(fqn, dst);
  2135. }
  2136. else static if (hasPlainMangling!FT)
  2137. {
  2138. dst.length = fqn.length;
  2139. dst[] = fqn[];
  2140. return dst;
  2141. }
  2142. else static if (isExternCPP!FT)
  2143. {
  2144. static assert(0, "Can't mangle extern(C++) functions.");
  2145. }
  2146. else
  2147. {
  2148. static assert(0, "Can't mangle function with unknown linkage ("~FT.stringof~").");
  2149. }
  2150. }
  2151. private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi";
  2152. @safe pure nothrow unittest
  2153. {
  2154. assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
  2155. static if (hasTypeBackRef)
  2156. {
  2157. assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQsZi");
  2158. assert(mangleFunc!(int function(Object, Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQsQdZi");
  2159. }
  2160. else
  2161. {
  2162. auto mngl = mangleFunc!(int function(Object))("object.Object.opEquals");
  2163. assert(mngl == "_D6object6Object8opEqualsFC6ObjectZi");
  2164. auto remngl = reencodeMangled(mngl);
  2165. assert(remngl == "_D6object6Object8opEqualsFCQsZi");
  2166. }
  2167. // trigger back tracking with ambiguity on '__T', template or identifier
  2168. assert(reencodeMangled("_D3std4conv4conv7__T3std4convi") == "_D3std4convQf7__T3stdQpi");
  2169. }
  2170. @safe pure nothrow unittest
  2171. {
  2172. int function(lazy int[], ...) fp;
  2173. assert(mangle!(typeof(fp))("demangle.test") == "_D8demangle4testPFLAiYi");
  2174. assert(mangle!(typeof(*fp))("demangle.test") == "_D8demangle4testFLAiYi");
  2175. }
  2176. private template isExternD(FT) if (is(FT == function))
  2177. {
  2178. enum isExternD = __traits(getLinkage, FT) == "D";
  2179. }
  2180. private template isExternCPP(FT) if (is(FT == function))
  2181. {
  2182. enum isExternCPP = __traits(getLinkage, FT) == "C++";
  2183. }
  2184. private template hasPlainMangling(FT) if (is(FT == function))
  2185. {
  2186. enum lnk = __traits(getLinkage, FT);
  2187. // C || Windows
  2188. enum hasPlainMangling = lnk == "C" || lnk == "Windows" || lnk == "System";
  2189. }
  2190. @safe pure nothrow unittest
  2191. {
  2192. static extern(D) void fooD();
  2193. static extern(C) void fooC();
  2194. static extern(Windows) void fooW();
  2195. static extern(C++) void fooCPP();
  2196. bool check(FT)(bool isD, bool isCPP, bool isPlain)
  2197. {
  2198. return isExternD!FT == isD && isExternCPP!FT == isCPP &&
  2199. hasPlainMangling!FT == isPlain;
  2200. }
  2201. static assert(check!(typeof(fooD))(true, false, false));
  2202. static assert(check!(typeof(fooC))(false, false, true));
  2203. static assert(check!(typeof(fooW))(false, false, true));
  2204. static assert(check!(typeof(fooCPP))(false, true, false));
  2205. static assert(__traits(compiles, mangleFunc!(typeof(&fooD))("")));
  2206. static assert(__traits(compiles, mangleFunc!(typeof(&fooC))("")));
  2207. static assert(__traits(compiles, mangleFunc!(typeof(&fooW))("")));
  2208. static assert(!__traits(compiles, mangleFunc!(typeof(&fooCPP))("")));
  2209. }
  2210. /***
  2211. * C name mangling is done by adding a prefix on some platforms.
  2212. */
  2213. version (Win32)
  2214. enum string cPrefix = "_";
  2215. else version (Darwin)
  2216. enum string cPrefix = "_";
  2217. else
  2218. enum string cPrefix = "";
  2219. @safe pure nothrow unittest
  2220. {
  2221. immutable string[2][] table =
  2222. [
  2223. ["printf", "printf"],
  2224. ["_foo", "_foo"],
  2225. ["_D88", "_D88"],
  2226. ["_D3fooQeFIAyaZv", "void foo.foo(in immutable(char)[])" ],
  2227. ["_D3barQeFIKAyaZv", "void bar.bar(in ref immutable(char)[])" ],
  2228. ["_D4test3fooAa", "char[] test.foo"],
  2229. ["_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])"],
  2230. ["_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(Object)"],
  2231. ["_D4test2dgDFiYd", "double delegate(int, ...) test.dg"],
  2232. ["_D4test2dgDxFNfiYd", "double delegate(int, ...) @safe const test.dg"],
  2233. //["_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", ""],
  2234. //["_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", ""],
  2235. ["_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(\"abc\"w, \"def\"d).x"],
  2236. ["_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy Object, lazy int delegate(lazy int))"],
  2237. ["_D8demangle4testFAiXi", "int demangle.test(int[]...)"],
  2238. ["_D8demangle4testFAiYi", "int demangle.test(int[], ...)"],
  2239. ["_D8demangle4testFLAiXi", "int demangle.test(lazy int[]...)"],
  2240. ["_D8demangle4testFLAiYi", "int demangle.test(lazy int[], ...)"],
  2241. ["_D6plugin8generateFiiZAya", "immutable(char)[] plugin.generate(int, int)"],
  2242. ["_D6plugin8generateFiiZAxa", "const(char)[] plugin.generate(int, int)"],
  2243. ["_D6plugin8generateFiiZAOa", "shared(char)[] plugin.generate(int, int)"],
  2244. ["_D8demangle3fnAFZ3fnBMFZv", "void demangle.fnA().fnB()"],
  2245. ["_D8demangle4mainFZ1S3fnCMFZv", "void demangle.main().S.fnC()"],
  2246. ["_D8demangle4mainFZ1S3fnDMFZv", "void demangle.main().S.fnD()"],
  2247. ["_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv", "void demangle.fn!([1, 2, 3, 4]).fn()"],
  2248. ["_D8demangle10__T2fnVi1Z2fnFZv", "void demangle.fn!(1).fn()"],
  2249. ["_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv", "void demangle.fn!(demangle.S(1, 2)).fn()"],
  2250. ["_D8demangle13__T2fnVeeNANZ2fnFZv", "void demangle.fn!(real.nan).fn()"],
  2251. ["_D8demangle14__T2fnVeeNINFZ2fnFZv", "void demangle.fn!(-real.infinity).fn()"],
  2252. ["_D8demangle13__T2fnVeeINFZ2fnFZv", "void demangle.fn!(real.infinity).fn()"],
  2253. ["_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv", "void demangle.fn!([1:2, 3:4]).fn()"],
  2254. ["_D8demangle2fnFNgiZNgi", "inout(int) demangle.fn(inout(int))"],
  2255. ["_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv", "void demangle.fn!('a', '\\t', \\x00, '\\u0101', '\\U00010001').fn()"],
  2256. ["_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv",
  2257. "nothrow @nogc @safe void gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)"],
  2258. ["_D8serenity9persister6Sqlite69__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZ4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZ4Test",
  2259. "serenity.persister.Sqlite.__unittest6().Test serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)"],
  2260. ["_D8bug100274mainFZ5localMFZi","int bug10027.main().local()"],
  2261. ["_D8demangle4testFNhG16gZv", "void demangle.test(__vector(byte[16]))"],
  2262. ["_D8demangle4testFNhG8sZv", "void demangle.test(__vector(short[8]))"],
  2263. ["_D8demangle4testFNhG4iZv", "void demangle.test(__vector(int[4]))"],
  2264. ["_D8demangle4testFNhG2lZv", "void demangle.test(__vector(long[2]))"],
  2265. ["_D8demangle4testFNhG4fZv", "void demangle.test(__vector(float[4]))"],
  2266. ["_D8demangle4testFNhG2dZv", "void demangle.test(__vector(double[2]))"],
  2267. ["_D8demangle4testFNhG4fNhG4fZv", "void demangle.test(__vector(float[4]), __vector(float[4]))"],
  2268. ["_D8bug1119234__T3fooS23_D8bug111924mainFZ3bariZ3fooMFZv","void bug11192.foo!(bug11192.main().bar).foo()"],
  2269. ["_D13libd_demangle12__ModuleInfoZ", "libd_demangle.__ModuleInfo"],
  2270. ["_D15TypeInfo_Struct6__vtblZ", "TypeInfo_Struct.__vtbl"],
  2271. ["_D3std5stdio12__ModuleInfoZ", "std.stdio.__ModuleInfo"],
  2272. ["_D3std6traits15__T8DemangleTkZ8Demangle6__initZ", "std.traits.Demangle!(uint).Demangle.__init"],
  2273. ["_D3foo3Bar7__ClassZ", "foo.Bar.__Class"],
  2274. ["_D3foo3Bar6__vtblZ", "foo.Bar.__vtbl"],
  2275. ["_D3foo3Bar11__interfaceZ", "foo.Bar.__interface"],
  2276. ["_D3foo7__arrayZ", "foo.__array"],
  2277. ["_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
  2278. ["_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
  2279. ["_D4test22__T4funcVAyaa3_610a62Z4funcFNaNbNiNmNfZAya", `pure nothrow @nogc @live @safe immutable(char)[] test.func!("a\x0ab").func()`],
  2280. ["_D3foo3barFzkZzi", "cent foo.bar(ucent)"],
  2281. ["_D5bug145Class3fooMFNlZPv", "scope void* bug14.Class.foo()"],
  2282. ["_D5bug145Class3barMFNjZPv", "return void* bug14.Class.bar()"],
  2283. ["_D5bug143fooFMPvZPv", "void* bug14.foo(scope void*)"],
  2284. ["_D5bug143barFMNkPvZPv", "void* bug14.bar(scope return void*)"],
  2285. ["_D3std5range15__T4iotaTtTtTtZ4iotaFtttZ6Result7opIndexMNgFNaNbNiNfmZNgt",
  2286. "inout pure nothrow @nogc @safe inout(ushort) std.range.iota!(ushort, ushort, ushort).iota(ushort, ushort, ushort).Result.opIndex(ulong)"],
  2287. ["_D3std6format77__T6getNthVAyaa13_696e7465676572207769647468S233std6traits10isIntegralTiTkTkZ6getNthFNaNfkkkZi",
  2288. "pure @safe int std.format.getNth!(\"integer width\", std.traits.isIntegral, int, uint, uint).getNth(uint, uint, uint)"],
  2289. ["_D3std11parallelism42__T16RoundRobinBufferTDFKAaZvTDxFNaNdNeZbZ16RoundRobinBuffer5primeMFZv",
  2290. "void std.parallelism.RoundRobinBuffer!(void delegate(ref char[]), bool delegate() pure @property @trusted const).RoundRobinBuffer.prime()"],
  2291. ["_D6mangle__T8fun21753VSQv6S21753S1f_DQBj10__lambda71MFNaNbNiNfZvZQCbQp",
  2292. "void function() pure nothrow @nogc @safe mangle.fun21753!(mangle.S21753(mangle.__lambda71())).fun21753"],
  2293. // Lname '0'
  2294. ["_D3std9algorithm9iteration__T9MapResultSQBmQBlQBe005stripTAAyaZQBi7opSliceMFNaNbNiNfmmZSQDiQDhQDa__TQCtSQDyQDxQDq00QCmTQCjZQDq",
  2295. "pure nothrow @nogc @safe std.algorithm.iteration.MapResult!(std.algorithm.iteration.__anonymous.strip, "
  2296. ~"immutable(char)[][]).MapResult std.algorithm.iteration.MapResult!(std.algorithm.iteration.strip, immutable(char)[][]).MapResult.opSlice(ulong, ulong)"],
  2297. // back references
  2298. ["_D4core4stdc5errnoQgFZi", "int core.stdc.errno.errno()"], // identifier back reference
  2299. ["_D4testFS10structnameQnZb", "bool test(structname, structname)"], // type back reference
  2300. ["_D3std11parallelism__T4TaskS8unittest3cmpTAyaTQeZQBb6__dtorMFNfZv",
  2301. "@safe void std.parallelism.Task!(unittest.cmp, immutable(char)[], immutable(char)[]).Task.__dtor()"],
  2302. // 1.s.s.foo from https://issues.dlang.org/show_bug.cgi?id=15831
  2303. ["_D13testexpansion44__T1sTS13testexpansion8__T1sTiZ1sFiZ6ResultZ1sFS13testexpansion8__T1sTiZ1sFiZ6ResultZ6Result3fooMFNaNfZv",
  2304. "pure @safe void testexpansion.s!(testexpansion.s!(int).s(int).Result).s(testexpansion.s!(int).s(int).Result).Result.foo()"],
  2305. ["_D13testexpansion__T1sTSQw__TQjTiZQoFiZ6ResultZQBbFQBcZQq3fooMFNaNfZv",
  2306. "pure @safe void testexpansion.s!(testexpansion.s!(int).s(int).Result).s(testexpansion.s!(int).s(int).Result).Result.foo()"],
  2307. // formerly ambiguous on 'V', template value argument or pascal function
  2308. // pascal functions have now been removed (in v2.095.0)
  2309. ["_D3std4conv__T7enumRepTyAaTEQBa12experimental9allocator15building_blocks15stats_collector7OptionsVQCti64ZQDnyQDh",
  2310. "immutable(char[]) std.conv.enumRep!(immutable(char[]), std.experimental.allocator.building_blocks.stats_collector.Options, 64).enumRep"],
  2311. // symbol back reference to location with symbol back reference
  2312. ["_D3std12experimental9allocator6common__T10reallocateTSQCaQBzQBo15building_blocks17kernighan_ritchie__T8KRRegionTSQEhQEgQDvQCh14null_allocator13NullAllocatorZQCdZQErFNaNbNiKQEpKAvmZb",
  2313. "pure nothrow @nogc bool std.experimental.allocator.common.reallocate!(std.experimental.allocator.building_blocks.kernighan_ritchie.KRRegion!("
  2314. ~"std.experimental.allocator.building_blocks.null_allocator.NullAllocator).KRRegion).reallocate(ref "
  2315. ~"std.experimental.allocator.building_blocks.kernighan_ritchie.KRRegion!(std.experimental.allocator.building_blocks.null_allocator.NullAllocator).KRRegion, ref void[], ulong)"],
  2316. ["_D3std9exception__T11doesPointToTASQBh5regex8internal2ir10NamedGroupTQBkTvZQCeFNaNbNiNeKxASQDlQCeQCbQBvQBvKxQtZb",
  2317. "pure nothrow @nogc @trusted bool std.exception.doesPointTo!(std.regex.internal.ir.NamedGroup[], "
  2318. ~"std.regex.internal.ir.NamedGroup[], void).doesPointTo(ref const(std.regex.internal.ir.NamedGroup[]), ref const(std.regex.internal.ir.NamedGroup[]))"],
  2319. ["_D3std9algorithm9iteration__T14SplitterResultS_DQBu3uni7isWhiteFNaNbNiNfwZbTAyaZQBz9__xtoHashFNbNeKxSQDvQDuQDn__TQDgS_DQEnQCtQCsQCnTQCeZQEdZm",
  2320. "nothrow @trusted ulong std.algorithm.iteration.SplitterResult!(std.uni.isWhite(dchar), immutable(char)[]).SplitterResult."
  2321. ~"__xtoHash(ref const(std.algorithm.iteration.SplitterResult!(std.uni.isWhite, immutable(char)[]).SplitterResult))"],
  2322. ["_D3std8typecons__T7TypedefTCQBaQz19__unittestL6513_208FNfZ7MyClassVQBonVAyanZQCh6__ctorMFNaNbNcNiNfQCuZSQDyQDx__TQDrTQDmVQDqnVQCcnZQEj",
  2323. "pure nothrow ref @nogc @safe std.typecons.Typedef!(std.typecons.__unittestL6513_208().MyClass, null, null).Typedef "
  2324. ~"std.typecons.Typedef!(std.typecons.__unittestL6513_208().MyClass, null, null).Typedef.__ctor(std.typecons.__unittestL6513_208().MyClass)"],
  2325. ["_D3std6getopt__TQkTAyaTDFNaNbNiNfQoZvTQtTDQsZQBnFNfKAQBiQBlQBkQBrQyZSQCpQCo12GetoptResult",
  2326. "@safe std.getopt.GetoptResult std.getopt.getopt!(immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe, "
  2327. ~"immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe)."
  2328. ~"getopt(ref immutable(char)[][], immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe, "
  2329. ~"immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe)"],
  2330. ["_D3std5regex8internal9kickstart__T7ShiftOrTaZQl11ShiftThread__T3setS_DQCqQCpQCmQCg__TQBzTaZQCfQBv10setInvMaskMFNaNbNiNfkkZvZQCjMFNaNfwZv",
  2331. "pure @safe void std.regex.internal.kickstart.ShiftOr!(char).ShiftOr.ShiftThread.set!(std.regex.internal.kickstart.ShiftOr!(char).ShiftOr.ShiftThread.setInvMask(uint, uint)).set(dchar)"],
  2332. ["_D3std5stdio4File__T8lockImplX10LockFileExTykZQBaMFmmykZi", // C function as template alias parameter
  2333. "int std.stdio.File.lockImpl!(LockFileEx, immutable(uint)).lockImpl(ulong, ulong, immutable(uint))"],
  2334. // back reference for type in template AA parameter value
  2335. ["_D3std9algorithm9iteration__T12FilterResultSQBq8typecons__T5TupleTiVAyaa1_61TiVQla1_62TiVQva1_63ZQBm__T6renameVHiQBtA2i0a1_63i2a1_61ZQBeMFNcZ9__lambda1TAiZQEw9__xtoHashFNbNeKxSQGsQGrQGk__TQGdSQHiQFs__TQFmTiVQFja1_61TiVQFua1_62TiVQGfa1_63ZQGx__TQFlVQFhA2i0a1_63i2a1_61ZQGjMFNcZQFfTQEyZQJvZm",
  2336. `nothrow @trusted ulong std.algorithm.iteration.FilterResult!(std.typecons.Tuple!(int, "a", int, "b", int, "c").`
  2337. ~`Tuple.rename!([0:"c", 2:"a"]).rename().__lambda1, int[]).FilterResult.__xtoHash(ref const(std.algorithm.iteration.`
  2338. ~`FilterResult!(std.typecons.Tuple!(int, "a", int, "b", int, "c").Tuple.rename!([0:"c", 2:"a"]).rename().__lambda1, int[]).FilterResult))`],
  2339. ["_D4test4rrs1FKPiZv", "void test.rrs1(ref int*)"],
  2340. ["_D4test4rrs1FMNkJPiZv", "void test.rrs1(scope return out int*)"],
  2341. ["_D4test4rrs1FMNkKPiZv", "void test.rrs1(scope return ref int*)"],
  2342. ["_D4test4rrs1FNkJPiZv", "void test.rrs1(return out int*)"],
  2343. ["_D4test4rrs1FNkKPiZv", "void test.rrs1(return ref int*)"],
  2344. ["_D4test4rrs1FNkMJPiZv", "void test.rrs1(return scope out int*)"],
  2345. ["_D4test4rrs1FNkMKPiZv", "void test.rrs1(return scope ref int*)"],
  2346. ["_D4test4rrs1FNkMPiZv", "void test.rrs1(return scope int*)"],
  2347. ];
  2348. template staticIota(int x)
  2349. {
  2350. template Seq(T...){ alias Seq = T; }
  2351. static if (x == 0)
  2352. alias staticIota = Seq!();
  2353. else
  2354. alias staticIota = Seq!(staticIota!(x - 1), x - 1);
  2355. }
  2356. foreach ( i, name; table )
  2357. {
  2358. auto r = demangle( name[0] );
  2359. assert( r == name[1],
  2360. "demangled `" ~ name[0] ~ "` as `" ~ r ~ "` but expected `" ~ name[1] ~ "`");
  2361. }
  2362. foreach ( i; staticIota!(table.length) )
  2363. {
  2364. enum r = demangle( table[i][0] );
  2365. static assert( r == table[i][1],
  2366. "demangled `" ~ table[i][0] ~ "` as `" ~ r ~ "` but expected `" ~ table[i][1] ~ "`");
  2367. }
  2368. {
  2369. // https://issues.dlang.org/show_bug.cgi?id=18531
  2370. auto symbol = `_D3std3uni__T6toCaseS_DQvQt12toLowerIndexFNaNbNiNewZtVii1043S_DQCjQCi10toLowerTabFNaNbNiNemZwSQDo5ascii7toLowerTAyaZQDzFNaNeQmZ14__foreachbody2MFNaNeKmKwZ14__foreachbody3MFNaNeKwZi`;
  2371. auto demangled = `pure @trusted int std.uni.toCase!(std.uni.toLowerIndex(dchar), 1043, std.uni.toLowerTab(ulong), std.ascii.toLower, immutable(char)[]).toCase(immutable(char)[]).__foreachbody2(ref ulong, ref dchar).__foreachbody3(ref dchar)`;
  2372. auto dst = new char[200];
  2373. auto ret = demangle( symbol, dst);
  2374. assert( ret == demangled );
  2375. }
  2376. }
  2377. unittest
  2378. {
  2379. // https://issues.dlang.org/show_bug.cgi?id=18300
  2380. string s = demangle.mangleof;
  2381. foreach (i; 1..77)
  2382. {
  2383. char[] buf = new char[i];
  2384. auto ds = demangle(s, buf);
  2385. assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[])" ||
  2386. ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[])");
  2387. }
  2388. }
  2389. unittest
  2390. {
  2391. // https://issues.dlang.org/show_bug.cgi?id=18300
  2392. string s = "_D1";
  2393. string expected = "int ";
  2394. foreach (_; 0..10_000)
  2395. {
  2396. s ~= "a1";
  2397. expected ~= "a.";
  2398. }
  2399. s ~= "FiZi";
  2400. expected ~= "F";
  2401. assert(s.demangle == expected);
  2402. }
  2403. // https://issues.dlang.org/show_bug.cgi?id=22235
  2404. unittest
  2405. {
  2406. enum parent = __MODULE__ ~ '.' ~ __traits(identifier, __traits(parent, {}));
  2407. static noreturn abort() { assert(false); }
  2408. assert(demangle(abort.mangleof) == "pure nothrow @nogc @safe noreturn " ~ parent ~ "().abort()");
  2409. static void accept(noreturn) {}
  2410. assert(demangle(accept.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().accept(noreturn)");
  2411. static void templ(T)(T, T) {}
  2412. assert(demangle(templ!noreturn.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().templ!(noreturn).templ(noreturn, noreturn)");
  2413. static struct S(T) {}
  2414. static void aggr(S!noreturn) { assert(0); }
  2415. assert(demangle(aggr.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().aggr(" ~ parent ~ "().S!(noreturn).S)");
  2416. }
  2417. /*
  2418. *
  2419. */
  2420. string decodeDmdString( const(char)[] ln, ref size_t p ) nothrow pure @safe
  2421. {
  2422. string s;
  2423. uint zlen, zpos;
  2424. // decompress symbol
  2425. while ( p < ln.length )
  2426. {
  2427. int ch = cast(ubyte) ln[p++];
  2428. if ( (ch & 0xc0) == 0xc0 )
  2429. {
  2430. zlen = (ch & 0x7) + 1;
  2431. zpos = ((ch >> 3) & 7) + 1; // + zlen;
  2432. if ( zpos > s.length )
  2433. break;
  2434. s ~= s[$ - zpos .. $ - zpos + zlen];
  2435. }
  2436. else if ( ch >= 0x80 )
  2437. {
  2438. if ( p >= ln.length )
  2439. break;
  2440. int ch2 = cast(ubyte) ln[p++];
  2441. zlen = (ch2 & 0x7f) | ((ch & 0x38) << 4);
  2442. if ( p >= ln.length )
  2443. break;
  2444. int ch3 = cast(ubyte) ln[p++];
  2445. zpos = (ch3 & 0x7f) | ((ch & 7) << 7);
  2446. if ( zpos > s.length )
  2447. break;
  2448. s ~= s[$ - zpos .. $ - zpos + zlen];
  2449. }
  2450. else if ( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' )
  2451. s ~= cast(char) ch;
  2452. else
  2453. {
  2454. p--;
  2455. break;
  2456. }
  2457. }
  2458. return s;
  2459. }
  2460. // locally purified for internal use here only
  2461. extern (C) private
  2462. {
  2463. pure @trusted @nogc nothrow pragma(mangle, "fakePureReprintReal") void pureReprintReal(char[] nptr);
  2464. void fakePureReprintReal(char[] nptr)
  2465. {
  2466. import core.stdc.stdlib : strtold;
  2467. import core.stdc.stdio : snprintf;
  2468. import core.stdc.errno : errno;
  2469. const err = errno;
  2470. real val = strtold(nptr.ptr, null);
  2471. snprintf(nptr.ptr, nptr.length, "%#Lg", val);
  2472. errno = err;
  2473. }
  2474. }