12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783 |
- /**
- * The demangle module converts mangled D symbols to a representation similar
- * to what would have existed in code.
- *
- * Copyright: Copyright Sean Kelly 2010 - 2014.
- * License: Distributed under the
- * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
- * (See accompanying file LICENSE)
- * Authors: Sean Kelly
- * Source: $(DRUNTIMESRC core/_demangle.d)
- */
- module core.demangle;
- version (OSX)
- version = Darwin;
- else version (iOS)
- version = Darwin;
- else version (TVOS)
- version = Darwin;
- else version (WatchOS)
- version = Darwin;
- debug(trace) import core.stdc.stdio : printf;
- debug(info) import core.stdc.stdio : printf;
- private struct NoHooks
- {
- // supported hooks
- // static bool parseLName(ref Demangle);
- // static char[] parseType(ref Demangle, char[])
- }
- private struct Demangle(Hooks = NoHooks)
- {
- // NOTE: This implementation currently only works with mangled function
- // names as they exist in an object file. Type names mangled via
- // the .mangleof property are effectively incomplete as far as the
- // ABI is concerned and so are not considered to be mangled symbol
- // names.
- // NOTE: This implementation builds the demangled buffer in place by
- // writing data as it is decoded and then rearranging it later as
- // needed. In practice this results in very little data movement,
- // and the performance cost is more than offset by the gain from
- // not allocating dynamic memory to assemble the name piecemeal.
- //
- // If the destination buffer is too small, parsing will restart
- // with a larger buffer. Since this generally means only one
- // allocation during the course of a parsing run, this is still
- // faster than assembling the result piecemeal.
- pure @safe:
- enum AddType { no, yes }
- this( return scope const(char)[] buf_, return scope char[] dst_ = null )
- {
- this( buf_, AddType.yes, dst_ );
- }
- this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null )
- {
- buf = buf_;
- addType = addType_;
- dst = dst_;
- }
- enum size_t minBufSize = 4000;
- const(char)[] buf = null;
- char[] dst = null;
- size_t pos = 0;
- size_t len = 0;
- size_t brp = 0; // current back reference pos
- AddType addType = AddType.yes;
- bool mute = false;
- Hooks hooks;
- static class ParseException : Exception
- {
- @safe pure nothrow this( string msg )
- {
- super( msg );
- }
- }
- static class OverflowException : Exception
- {
- @safe pure nothrow this( string msg )
- {
- super( msg );
- }
- }
- static void error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */
- {
- pragma(inline, false); // tame dmd inliner
- //throw new ParseException( msg );
- debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
- throw __ctfe ? new ParseException(msg)
- : cast(ParseException) __traits(initSymbol, ParseException).ptr;
- }
- static void overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */
- {
- pragma(inline, false); // tame dmd inliner
- //throw new OverflowException( msg );
- debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
- throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
- }
- //////////////////////////////////////////////////////////////////////////
- // Type Testing and Conversion
- //////////////////////////////////////////////////////////////////////////
- static bool isAlpha( char val )
- {
- return ('a' <= val && 'z' >= val) ||
- ('A' <= val && 'Z' >= val) ||
- (0x80 & val); // treat all unicode as alphabetic
- }
- static bool isDigit( char val )
- {
- return '0' <= val && '9' >= val;
- }
- static bool isHexDigit( char val )
- {
- return ('0' <= val && '9' >= val) ||
- ('a' <= val && 'f' >= val) ||
- ('A' <= val && 'F' >= val);
- }
- static ubyte ascii2hex( char val )
- {
- if (val >= 'a' && val <= 'f')
- return cast(ubyte)(val - 'a' + 10);
- if (val >= 'A' && val <= 'F')
- return cast(ubyte)(val - 'A' + 10);
- if (val >= '0' && val <= '9')
- return cast(ubyte)(val - '0');
- error();
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- // Data Output
- //////////////////////////////////////////////////////////////////////////
- static bool contains( const(char)[] a, const(char)[] b ) @trusted
- {
- if (a.length && b.length)
- {
- auto bend = b.ptr + b.length;
- auto aend = a.ptr + a.length;
- return a.ptr <= b.ptr && bend <= aend;
- }
- return false;
- }
- // move val to the end of the dst buffer
- char[] shift( const(char)[] val )
- {
- pragma(inline, false); // tame dmd inliner
- if ( val.length && !mute )
- {
- assert( contains( dst[0 .. len], val ) );
- debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
- if (len + val.length > dst.length)
- overflow();
- size_t v = &val[0] - &dst[0];
- dst[len .. len + val.length] = val[];
- for (size_t p = v; p < len; p++)
- dst[p] = dst[p + val.length];
- return dst[len - val.length .. len];
- }
- return null;
- }
- // remove val from dst buffer
- void remove( const(char)[] val )
- {
- pragma(inline, false); // tame dmd inliner
- if ( val.length )
- {
- assert( contains( dst[0 .. len], val ) );
- debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr );
- size_t v = &val[0] - &dst[0];
- assert( len >= val.length && len <= dst.length );
- len -= val.length;
- for (size_t p = v; p < len; p++)
- dst[p] = dst[p + val.length];
- }
- }
- char[] append( const(char)[] val ) return scope
- {
- pragma(inline, false); // tame dmd inliner
- if ( val.length && !mute )
- {
- if ( !dst.length )
- dst.length = minBufSize;
- assert( !contains( dst[0 .. len], val ) );
- debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
- if ( dst.length - len >= val.length && &dst[len] == &val[0] )
- {
- // data is already in place
- auto t = dst[len .. len + val.length];
- len += val.length;
- return t;
- }
- if ( dst.length - len >= val.length )
- {
- dst[len .. len + val.length] = val[];
- auto t = dst[len .. len + val.length];
- len += val.length;
- return t;
- }
- overflow();
- }
- return null;
- }
- void putComma(size_t n)
- {
- pragma(inline, false);
- if (n)
- put(", ");
- }
- char[] put(char c) return scope
- {
- char[1] val = c;
- return put(val[]);
- }
- char[] put( scope const(char)[] val ) return scope
- {
- pragma(inline, false); // tame dmd inliner
- if ( val.length )
- {
- if ( !contains( dst[0 .. len], val ) )
- return append( val );
- return shift( val );
- }
- return null;
- }
- void putAsHex( size_t val, int width = 0 )
- {
- import core.internal.string;
- UnsignedStringBuf buf = void;
- auto s = unsignedToTempString!16(val, buf);
- int slen = cast(int)s.length;
- if (slen < width)
- {
- foreach (i; slen .. width)
- put('0');
- }
- put(s);
- }
- void pad( const(char)[] val )
- {
- if ( val.length )
- {
- append( " " );
- put( val );
- }
- }
- void silent( void delegate() pure @safe dg )
- {
- debug(trace) printf( "silent+\n" );
- debug(trace) scope(success) printf( "silent-\n" );
- auto n = len; dg(); len = n;
- }
- //////////////////////////////////////////////////////////////////////////
- // Parsing Utility
- //////////////////////////////////////////////////////////////////////////
- @property bool empty()
- {
- return pos >= buf.length;
- }
- @property char front()
- {
- if ( pos < buf.length )
- return buf[pos];
- return char.init;
- }
- char peek( size_t n )
- {
- if ( pos + n < buf.length )
- return buf[pos + n];
- return char.init;
- }
- void test( char val )
- {
- if ( val != front )
- error();
- }
- void popFront()
- {
- if ( pos++ >= buf.length )
- error();
- }
- void popFront(int i)
- {
- while (i--)
- popFront();
- }
- void match( char val )
- {
- test( val );
- popFront();
- }
- void match( const(char)[] val )
- {
- foreach (char e; val )
- {
- test( e );
- popFront();
- }
- }
- void eat( char val )
- {
- if ( val == front )
- popFront();
- }
- bool isSymbolNameFront()
- {
- char val = front;
- if ( isDigit( val ) || val == '_' )
- return true;
- if ( val != 'Q' )
- return false;
- // check the back reference encoding after 'Q'
- val = peekBackref();
- return isDigit( val ); // identifier ref
- }
- // return the first character at the back reference
- char peekBackref()
- {
- assert( front == 'Q' );
- auto n = decodeBackref!1();
- if (!n || n > pos)
- error("invalid back reference");
- return buf[pos - n];
- }
- size_t decodeBackref(size_t peekAt = 0)()
- {
- enum base = 26;
- size_t n = 0;
- for (size_t p; ; p++)
- {
- char t;
- static if (peekAt > 0)
- {
- t = peek(peekAt + p);
- }
- else
- {
- t = front;
- popFront();
- }
- if (t < 'A' || t > 'Z')
- {
- if (t < 'a' || t > 'z')
- error("invalid back reference");
- n = base * n + t - 'a';
- return n;
- }
- n = base * n + t - 'A';
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // Parsing Implementation
- //////////////////////////////////////////////////////////////////////////
- /*
- Number:
- Digit
- Digit Number
- */
- const(char)[] sliceNumber() return scope
- {
- debug(trace) printf( "sliceNumber+\n" );
- debug(trace) scope(success) printf( "sliceNumber-\n" );
- auto beg = pos;
- while ( true )
- {
- auto t = front;
- if (t >= '0' && t <= '9')
- popFront();
- else
- return buf[beg .. pos];
- }
- }
- size_t decodeNumber() scope
- {
- debug(trace) printf( "decodeNumber+\n" );
- debug(trace) scope(success) printf( "decodeNumber-\n" );
- return decodeNumber( sliceNumber() );
- }
- size_t decodeNumber( scope const(char)[] num ) scope
- {
- debug(trace) printf( "decodeNumber+\n" );
- debug(trace) scope(success) printf( "decodeNumber-\n" );
- size_t val = 0;
- foreach ( c; num )
- {
- import core.checkedint : mulu, addu;
- bool overflow = false;
- val = mulu(val, 10, overflow);
- val = addu(val, c - '0', overflow);
- if (overflow)
- error();
- }
- return val;
- }
- void parseReal() scope
- {
- debug(trace) printf( "parseReal+\n" );
- debug(trace) scope(success) printf( "parseReal-\n" );
- char[64] tbuf = void;
- size_t tlen = 0;
- real val = void;
- if ( 'I' == front )
- {
- match( "INF" );
- put( "real.infinity" );
- return;
- }
- if ( 'N' == front )
- {
- popFront();
- if ( 'I' == front )
- {
- match( "INF" );
- put( "-real.infinity" );
- return;
- }
- if ( 'A' == front )
- {
- match( "AN" );
- put( "real.nan" );
- return;
- }
- tbuf[tlen++] = '-';
- }
- tbuf[tlen++] = '0';
- tbuf[tlen++] = 'X';
- if ( !isHexDigit( front ) )
- error( "Expected hex digit" );
- tbuf[tlen++] = front;
- tbuf[tlen++] = '.';
- popFront();
- while ( isHexDigit( front ) )
- {
- tbuf[tlen++] = front;
- popFront();
- }
- match( 'P' );
- tbuf[tlen++] = 'p';
- if ( 'N' == front )
- {
- tbuf[tlen++] = '-';
- popFront();
- }
- else
- {
- tbuf[tlen++] = '+';
- }
- while ( isDigit( front ) )
- {
- tbuf[tlen++] = front;
- popFront();
- }
- tbuf[tlen] = 0;
- debug(info) printf( "got (%s)\n", tbuf.ptr );
- pureReprintReal( tbuf[] );
- debug(info) printf( "converted (%.*s)\n", cast(int) tlen, tbuf.ptr );
- put( tbuf[0 .. tlen] );
- }
- /*
- LName:
- Number Name
- Name:
- Namestart
- Namestart Namechars
- Namestart:
- _
- Alpha
- Namechar:
- Namestart
- Digit
- Namechars:
- Namechar
- Namechar Namechars
- */
- void parseLName() scope
- {
- debug(trace) printf( "parseLName+\n" );
- debug(trace) scope(success) printf( "parseLName-\n" );
- static if (__traits(hasMember, Hooks, "parseLName"))
- if (hooks.parseLName(this))
- return;
- if ( front == 'Q' )
- {
- // back reference to LName
- auto refPos = pos;
- popFront();
- size_t n = decodeBackref();
- if ( !n || n > refPos )
- error( "Invalid LName back reference" );
- if ( !mute )
- {
- auto savePos = pos;
- scope(exit) pos = savePos;
- pos = refPos - n;
- parseLName();
- }
- return;
- }
- auto n = decodeNumber();
- if ( n == 0 )
- {
- put( "__anonymous" );
- return;
- }
- if ( n > buf.length || n > buf.length - pos )
- error( "LName must be at least 1 character" );
- if ( '_' != front && !isAlpha( front ) )
- error( "Invalid character in LName" );
- foreach (char e; buf[pos + 1 .. pos + n] )
- {
- if ( '_' != e && !isAlpha( e ) && !isDigit( e ) )
- error( "Invalid character in LName" );
- }
- put( buf[pos .. pos + n] );
- pos += n;
- }
- /*
- Type:
- Shared
- Const
- Immutable
- Wild
- TypeArray
- TypeVector
- TypeStaticArray
- TypeAssocArray
- TypePointer
- TypeFunction
- TypeIdent
- TypeClass
- TypeStruct
- TypeEnum
- TypeTypedef
- TypeDelegate
- TypeNone
- TypeVoid
- TypeNoreturn
- TypeByte
- TypeUbyte
- TypeShort
- TypeUshort
- TypeInt
- TypeUint
- TypeLong
- TypeUlong
- TypeCent
- TypeUcent
- TypeFloat
- TypeDouble
- TypeReal
- TypeIfloat
- TypeIdouble
- TypeIreal
- TypeCfloat
- TypeCdouble
- TypeCreal
- TypeBool
- TypeChar
- TypeWchar
- TypeDchar
- TypeTuple
- Shared:
- O Type
- Const:
- x Type
- Immutable:
- y Type
- Wild:
- Ng Type
- TypeArray:
- A Type
- TypeVector:
- Nh Type
- TypeStaticArray:
- G Number Type
- TypeAssocArray:
- H Type Type
- TypePointer:
- P Type
- TypeFunction:
- CallConvention FuncAttrs Arguments ArgClose Type
- TypeIdent:
- I LName
- TypeClass:
- C LName
- TypeStruct:
- S LName
- TypeEnum:
- E LName
- TypeTypedef:
- T LName
- TypeDelegate:
- D TypeFunction
- TypeNone:
- n
- TypeVoid:
- v
- TypeNoreturn
- Nn
- TypeByte:
- g
- TypeUbyte:
- h
- TypeShort:
- s
- TypeUshort:
- t
- TypeInt:
- i
- TypeUint:
- k
- TypeLong:
- l
- TypeUlong:
- m
- TypeCent
- zi
- TypeUcent
- zk
- TypeFloat:
- f
- TypeDouble:
- d
- TypeReal:
- e
- TypeIfloat:
- o
- TypeIdouble:
- p
- TypeIreal:
- j
- TypeCfloat:
- q
- TypeCdouble:
- r
- TypeCreal:
- c
- TypeBool:
- b
- TypeChar:
- a
- TypeWchar:
- u
- TypeDchar:
- w
- TypeTuple:
- B Number Arguments
- */
- char[] parseType( char[] name = null ) return scope
- {
- static immutable string[23] primitives = [
- "char", // a
- "bool", // b
- "creal", // c
- "double", // d
- "real", // e
- "float", // f
- "byte", // g
- "ubyte", // h
- "int", // i
- "ireal", // j
- "uint", // k
- "long", // l
- "ulong", // m
- null, // n
- "ifloat", // o
- "idouble", // p
- "cfloat", // q
- "cdouble", // r
- "short", // s
- "ushort", // t
- "wchar", // u
- "void", // v
- "dchar", // w
- ];
- static if (__traits(hasMember, Hooks, "parseType"))
- if (auto n = hooks.parseType(this, name))
- return n;
- debug(trace) printf( "parseType+\n" );
- debug(trace) scope(success) printf( "parseType-\n" );
- auto beg = len;
- auto t = front;
- char[] parseBackrefType(scope char[] delegate() pure @safe parseDg) pure @safe
- {
- if (pos == brp)
- error("recursive back reference");
- auto refPos = pos;
- popFront();
- auto n = decodeBackref();
- if (n == 0 || n > pos)
- error("invalid back reference");
- if ( mute )
- return null;
- auto savePos = pos;
- auto saveBrp = brp;
- scope(success) { pos = savePos; brp = saveBrp; }
- pos = refPos - n;
- brp = refPos;
- auto ret = parseDg();
- return ret;
- }
- switch ( t )
- {
- case 'Q': // Type back reference
- return parseBackrefType( () => parseType( name ) );
- case 'O': // Shared (O Type)
- popFront();
- put( "shared(" );
- parseType();
- put( ')' );
- pad( name );
- return dst[beg .. len];
- case 'x': // Const (x Type)
- popFront();
- put( "const(" );
- parseType();
- put( ')' );
- pad( name );
- return dst[beg .. len];
- case 'y': // Immutable (y Type)
- popFront();
- put( "immutable(" );
- parseType();
- put( ')' );
- pad( name );
- return dst[beg .. len];
- case 'N':
- popFront();
- switch ( front )
- {
- case 'n': // Noreturn
- popFront();
- put("noreturn");
- return dst[beg .. len];
- case 'g': // Wild (Ng Type)
- popFront();
- // TODO: Anything needed here?
- put( "inout(" );
- parseType();
- put( ')' );
- return dst[beg .. len];
- case 'h': // TypeVector (Nh Type)
- popFront();
- put( "__vector(" );
- parseType();
- put( ')' );
- return dst[beg .. len];
- default:
- error();
- assert( 0 );
- }
- case 'A': // TypeArray (A Type)
- popFront();
- parseType();
- put( "[]" );
- pad( name );
- return dst[beg .. len];
- case 'G': // TypeStaticArray (G Number Type)
- popFront();
- auto num = sliceNumber();
- parseType();
- put( '[' );
- put( num );
- put( ']' );
- pad( name );
- return dst[beg .. len];
- case 'H': // TypeAssocArray (H Type Type)
- popFront();
- // skip t1
- auto tx = parseType();
- parseType();
- put( '[' );
- put( tx );
- put( ']' );
- pad( name );
- return dst[beg .. len];
- case 'P': // TypePointer (P Type)
- popFront();
- parseType();
- put( '*' );
- pad( name );
- return dst[beg .. len];
- case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
- return parseTypeFunction( name );
- case 'C': // TypeClass (C LName)
- case 'S': // TypeStruct (S LName)
- case 'E': // TypeEnum (E LName)
- case 'T': // TypeTypedef (T LName)
- popFront();
- parseQualifiedName();
- pad( name );
- return dst[beg .. len];
- case 'D': // TypeDelegate (D TypeFunction)
- popFront();
- auto modbeg = len;
- parseModifier();
- auto modend = len;
- if ( front == 'Q' )
- parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) );
- else
- parseTypeFunction( name, IsDelegate.yes );
- if (modend > modbeg)
- {
- // move modifiers behind the function arguments
- shift(dst[modend-1 .. modend]); // trailing space
- shift(dst[modbeg .. modend-1]);
- }
- return dst[beg .. len];
- case 'n': // TypeNone (n)
- popFront();
- // TODO: Anything needed here?
- return dst[beg .. len];
- case 'B': // TypeTuple (B Number Arguments)
- popFront();
- // TODO: Handle this.
- return dst[beg .. len];
- case 'Z': // Internal symbol
- // This 'type' is used for untyped internal symbols, i.e.:
- // __array
- // __init
- // __vtbl
- // __Class
- // __Interface
- // __ModuleInfo
- popFront();
- return dst[beg .. len];
- default:
- if (t >= 'a' && t <= 'w')
- {
- popFront();
- put( primitives[cast(size_t)(t - 'a')] );
- pad( name );
- return dst[beg .. len];
- }
- else if (t == 'z')
- {
- popFront();
- switch ( front )
- {
- case 'i':
- popFront();
- put( "cent" );
- pad( name );
- return dst[beg .. len];
- case 'k':
- popFront();
- put( "ucent" );
- pad( name );
- return dst[beg .. len];
- default:
- error();
- assert( 0 );
- }
- }
- error();
- return null;
- }
- }
- /*
- TypeFunction:
- CallConvention FuncAttrs Arguments ArgClose Type
- CallConvention:
- F // D
- U // C
- W // Windows
- R // C++
- FuncAttrs:
- FuncAttr
- FuncAttr FuncAttrs
- FuncAttr:
- empty
- FuncAttrPure
- FuncAttrNothrow
- FuncAttrProperty
- FuncAttrRef
- FuncAttrReturn
- FuncAttrScope
- FuncAttrTrusted
- FuncAttrSafe
- FuncAttrPure:
- Na
- FuncAttrNothrow:
- Nb
- FuncAttrRef:
- Nc
- FuncAttrProperty:
- Nd
- FuncAttrTrusted:
- Ne
- FuncAttrSafe:
- Nf
- FuncAttrNogc:
- Ni
- FuncAttrReturn:
- Nj
- FuncAttrScope:
- Nl
- Arguments:
- Argument
- Argument Arguments
- Argument:
- Argument2
- M Argument2 // scope
- Argument2:
- Type
- J Type // out
- K Type // ref
- L Type // lazy
- ArgClose
- X // variadic T t,...) style
- Y // variadic T t...) style
- Z // not variadic
- */
- void parseCallConvention()
- {
- // CallConvention
- switch ( front )
- {
- case 'F': // D
- popFront();
- break;
- case 'U': // C
- popFront();
- put( "extern (C) " );
- break;
- case 'W': // Windows
- popFront();
- put( "extern (Windows) " );
- break;
- case 'R': // C++
- popFront();
- put( "extern (C++) " );
- break;
- default:
- error();
- }
- }
- void parseModifier()
- {
- switch ( front )
- {
- case 'y':
- popFront();
- put( "immutable " );
- break;
- case 'O':
- popFront();
- put( "shared " );
- if ( front == 'x' )
- goto case 'x';
- if ( front == 'N' )
- goto case 'N';
- break;
- case 'N':
- if ( peek( 1 ) != 'g' )
- break;
- popFront();
- popFront();
- put( "inout " );
- if ( front == 'x' )
- goto case 'x';
- break;
- case 'x':
- popFront();
- put( "const " );
- break;
- default: break;
- }
- }
- void parseFuncAttr()
- {
- // FuncAttrs
- breakFuncAttrs:
- while ('N' == front)
- {
- popFront();
- switch ( front )
- {
- case 'a': // FuncAttrPure
- popFront();
- put( "pure " );
- continue;
- case 'b': // FuncAttrNoThrow
- popFront();
- put( "nothrow " );
- continue;
- case 'c': // FuncAttrRef
- popFront();
- put( "ref " );
- continue;
- case 'd': // FuncAttrProperty
- popFront();
- put( "@property " );
- continue;
- case 'e': // FuncAttrTrusted
- popFront();
- put( "@trusted " );
- continue;
- case 'f': // FuncAttrSafe
- popFront();
- put( "@safe " );
- continue;
- case 'g':
- case 'h':
- case 'k':
- case 'n':
- // NOTE: The inout parameter type is represented as "Ng".
- // The vector parameter type is represented as "Nh".
- // The return parameter type is represented as "Nk".
- // The noreturn parameter type is represented as "Nn".
- // These make it look like a FuncAttr, but infact
- // if we see these, then we know we're really in
- // the parameter list. Rewind and break.
- pos--;
- break breakFuncAttrs;
- case 'i': // FuncAttrNogc
- popFront();
- put( "@nogc " );
- continue;
- case 'j': // FuncAttrReturn
- popFront();
- put( "return " );
- continue;
- case 'l': // FuncAttrScope
- popFront();
- put( "scope " );
- continue;
- case 'm': // FuncAttrLive
- popFront();
- put( "@live " );
- continue;
- default:
- error();
- }
- }
- }
- void parseFuncArguments() scope
- {
- // Arguments
- for ( size_t n = 0; true; n++ )
- {
- debug(info) printf( "tok (%c)\n", front );
- switch ( front )
- {
- case 'X': // ArgClose (variadic T t...) style)
- popFront();
- put( "..." );
- return;
- case 'Y': // ArgClose (variadic T t,...) style)
- popFront();
- put( ", ..." );
- return;
- case 'Z': // ArgClose (not variadic)
- popFront();
- return;
- default:
- break;
- }
- putComma(n);
- /* Do special return, scope, ref, out combinations
- */
- int npops;
- if ( 'M' == front && peek(1) == 'N' && peek(2) == 'k')
- {
- const c3 = peek(3);
- if (c3 == 'J')
- {
- put("scope return out "); // MNkJ
- npops = 4;
- }
- else if (c3 == 'K')
- {
- put("scope return ref "); // MNkK
- npops = 4;
- }
- }
- else if ('N' == front && peek(1) == 'k')
- {
- const c2 = peek(2);
- if (c2 == 'J')
- {
- put("return out "); // NkJ
- npops = 3;
- }
- else if (c2 == 'K')
- {
- put("return ref "); // NkK
- npops = 3;
- }
- else if (c2 == 'M')
- {
- const c3 = peek(3);
- if (c3 == 'J')
- {
- put("return scope out "); // NkMJ
- npops = 4;
- }
- else if (c3 == 'K')
- {
- put("return scope ref "); // NkMK
- npops = 4;
- }
- else
- {
- put("return scope "); // NkM
- npops = 3;
- }
- }
- }
- popFront(npops);
- if ( 'M' == front )
- {
- popFront();
- put( "scope " );
- }
- if ( 'N' == front )
- {
- popFront();
- if ( 'k' == front ) // Return (Nk Parameter2)
- {
- popFront();
- put( "return " );
- }
- else
- pos--;
- }
- switch ( front )
- {
- case 'I': // in (I Type)
- popFront();
- put("in ");
- if (front == 'K')
- goto case;
- parseType();
- continue;
- case 'K': // ref (K Type)
- popFront();
- put( "ref " );
- parseType();
- continue;
- case 'J': // out (J Type)
- popFront();
- put( "out " );
- parseType();
- continue;
- case 'L': // lazy (L Type)
- popFront();
- put( "lazy " );
- parseType();
- continue;
- default:
- parseType();
- }
- }
- }
- enum IsDelegate { no, yes }
- /*
- TypeFunction:
- CallConvention FuncAttrs Arguments ArgClose Type
- */
- char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
- {
- debug(trace) printf( "parseTypeFunction+\n" );
- debug(trace) scope(success) printf( "parseTypeFunction-\n" );
- auto beg = len;
- parseCallConvention();
- auto attrbeg = len;
- parseFuncAttr();
- auto argbeg = len;
- put( '(' );
- parseFuncArguments();
- put( ')' );
- if (attrbeg < argbeg)
- {
- // move function attributes behind arguments
- shift( dst[argbeg - 1 .. argbeg] ); // trailing space
- shift( dst[attrbeg .. argbeg - 1] ); // attributes
- argbeg = attrbeg;
- }
- auto retbeg = len;
- parseType();
- put( ' ' );
- // append name/delegate/function
- if ( name.length )
- {
- if ( !contains( dst[0 .. len], name ) )
- put( name );
- else if ( shift( name ).ptr != name.ptr )
- {
- argbeg -= name.length;
- retbeg -= name.length;
- }
- }
- else if ( IsDelegate.yes == isdg )
- put( "delegate" );
- else
- put( "function" );
- // move arguments and attributes behind name
- shift( dst[argbeg .. retbeg] );
- return dst[beg..len];
- }
- static bool isCallConvention( char ch )
- {
- switch ( ch )
- {
- case 'F', 'U', 'V', 'W', 'R':
- return true;
- default:
- return false;
- }
- }
- /*
- Value:
- n
- Number
- i Number
- N Number
- e HexFloat
- c HexFloat c HexFloat
- A Number Value...
- HexFloat:
- NAN
- INF
- NINF
- N HexDigits P Exponent
- HexDigits P Exponent
- Exponent:
- N Number
- Number
- HexDigits:
- HexDigit
- HexDigit HexDigits
- HexDigit:
- Digit
- A
- B
- C
- D
- E
- F
- */
- void parseValue(scope char[] name = null, char type = '\0' ) scope
- {
- debug(trace) printf( "parseValue+\n" );
- debug(trace) scope(success) printf( "parseValue-\n" );
- // printf( "*** %c\n", front );
- switch ( front )
- {
- case 'n':
- popFront();
- put( "null" );
- return;
- case 'i':
- popFront();
- if ( '0' > front || '9' < front )
- error( "Number expected" );
- goto case;
- case '0': .. case '9':
- parseIntegerValue( name, type );
- return;
- case 'N':
- popFront();
- put( '-' );
- parseIntegerValue( name, type );
- return;
- case 'e':
- popFront();
- parseReal();
- return;
- case 'c':
- popFront();
- parseReal();
- put( '+' );
- match( 'c' );
- parseReal();
- put( 'i' );
- return;
- case 'a': case 'w': case 'd':
- char t = front;
- popFront();
- auto n = decodeNumber();
- match( '_' );
- put( '"' );
- foreach (i; 0..n)
- {
- auto a = ascii2hex( front ); popFront();
- auto b = ascii2hex( front ); popFront();
- auto v = cast(char)((a << 4) | b);
- if (' ' <= v && v <= '~') // ASCII printable
- {
- put(v);
- }
- else
- {
- put("\\x");
- putAsHex(v, 2);
- }
- }
- put( '"' );
- if ( 'a' != t )
- put(t);
- return;
- case 'A':
- // NOTE: This is kind of a hack. An associative array literal
- // [1:2, 3:4] is represented as HiiA2i1i2i3i4, so the type
- // is "Hii" and the value is "A2i1i2i3i4". Thus the only
- // way to determine that this is an AA value rather than an
- // array value is for the caller to supply the type char.
- // Hopefully, this will change so that the value is
- // "H2i1i2i3i4", rendering this unnecesary.
- if ( 'H' == type )
- goto LassocArray;
- // A Number Value...
- // An array literal. Value is repeated Number times.
- popFront();
- put( '[' );
- auto n = decodeNumber();
- foreach ( i; 0 .. n )
- {
- putComma(i);
- parseValue();
- }
- put( ']' );
- return;
- case 'H':
- LassocArray:
- // H Number Value...
- // An associative array literal. Value is repeated 2*Number times.
- popFront();
- put( '[' );
- auto n = decodeNumber();
- foreach ( i; 0 .. n )
- {
- putComma(i);
- parseValue();
- put(':');
- parseValue();
- }
- put( ']' );
- return;
- case 'S':
- // S Number Value...
- // A struct literal. Value is repeated Number times.
- popFront();
- if ( name.length )
- put( name );
- put( '(' );
- auto n = decodeNumber();
- foreach ( i; 0 .. n )
- {
- putComma(i);
- parseValue();
- }
- put( ')' );
- return;
- case 'f':
- // f MangledName
- // A function literal symbol
- popFront();
- parseMangledName(false, 1);
- return;
- default:
- error();
- }
- }
- void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope
- {
- debug(trace) printf( "parseIntegerValue+\n" );
- debug(trace) scope(success) printf( "parseIntegerValue-\n" );
- switch ( type )
- {
- case 'a': // char
- case 'u': // wchar
- case 'w': // dchar
- {
- auto val = sliceNumber();
- auto num = decodeNumber( val );
- switch ( num )
- {
- case '\'':
- put( "'\\''" );
- return;
- // \", \?
- case '\\':
- put( "'\\\\'" );
- return;
- case '\a':
- put( "'\\a'" );
- return;
- case '\b':
- put( "'\\b'" );
- return;
- case '\f':
- put( "'\\f'" );
- return;
- case '\n':
- put( "'\\n'" );
- return;
- case '\r':
- put( "'\\r'" );
- return;
- case '\t':
- put( "'\\t'" );
- return;
- case '\v':
- put( "'\\v'" );
- return;
- default:
- switch ( type )
- {
- case 'a':
- if ( num >= 0x20 && num < 0x7F )
- {
- put( '\'' );
- put( cast(char)num );
- put( '\'' );
- return;
- }
- put( "\\x" );
- putAsHex( num, 2 );
- return;
- case 'u':
- put( "'\\u" );
- putAsHex( num, 4 );
- put( '\'' );
- return;
- case 'w':
- put( "'\\U" );
- putAsHex( num, 8 );
- put( '\'' );
- return;
- default:
- assert( 0 );
- }
- }
- }
- case 'b': // bool
- put( decodeNumber() ? "true" : "false" );
- return;
- case 'h', 't', 'k': // ubyte, ushort, uint
- put( sliceNumber() );
- put( 'u' );
- return;
- case 'l': // long
- put( sliceNumber() );
- put( 'L' );
- return;
- case 'm': // ulong
- put( sliceNumber() );
- put( "uL" );
- return;
- default:
- put( sliceNumber() );
- return;
- }
- }
- /*
- TemplateArgs:
- TemplateArg
- TemplateArg TemplateArgs
- TemplateArg:
- TemplateArgX
- H TemplateArgX
- TemplateArgX:
- T Type
- V Type Value
- S Number_opt QualifiedName
- X ExternallyMangledName
- */
- void parseTemplateArgs() scope
- {
- debug(trace) printf( "parseTemplateArgs+\n" );
- debug(trace) scope(success) printf( "parseTemplateArgs-\n" );
- L_nextArg:
- for ( size_t n = 0; true; n++ )
- {
- if ( front == 'H' )
- popFront();
- switch ( front )
- {
- case 'T':
- popFront();
- putComma(n);
- parseType();
- continue;
- case 'V':
- popFront();
- putComma(n);
- // NOTE: In the few instances where the type is actually
- // desired in the output it should precede the value
- // generated by parseValue, so it is safe to simply
- // decrement len and let put/append do its thing.
- char t = front; // peek at type for parseValue
- if ( t == 'Q' )
- t = peekBackref();
- char[] name; silent( delegate void() { name = parseType(); } );
- parseValue( name, t );
- continue;
- case 'S':
- popFront();
- putComma(n);
- if ( mayBeMangledNameArg() )
- {
- auto l = len;
- auto p = pos;
- auto b = brp;
- try
- {
- debug(trace) printf( "may be mangled name arg\n" );
- parseMangledNameArg();
- continue;
- }
- catch ( ParseException e )
- {
- len = l;
- pos = p;
- brp = b;
- debug(trace) printf( "not a mangled name arg\n" );
- }
- }
- if ( isDigit( front ) && isDigit( peek( 1 ) ) )
- {
- // ambiguity: length followed by qualified name (starting with number)
- // try all possible pairs of numbers
- auto qlen = decodeNumber() / 10; // last digit needed for QualifiedName
- pos--;
- auto l = len;
- auto p = pos;
- auto b = brp;
- while ( qlen > 0 )
- {
- try
- {
- parseQualifiedName();
- if ( pos == p + qlen )
- continue L_nextArg;
- }
- catch ( ParseException e )
- {
- }
- qlen /= 10; // retry with one digit less
- pos = --p;
- len = l;
- brp = b;
- }
- }
- parseQualifiedName();
- continue;
- case 'X':
- popFront();
- putComma(n);
- parseLName();
- continue;
- default:
- return;
- }
- }
- }
- bool mayBeMangledNameArg()
- {
- debug(trace) printf( "mayBeMangledNameArg+\n" );
- debug(trace) scope(success) printf( "mayBeMangledNameArg-\n" );
- auto p = pos;
- scope(exit) pos = p;
- if ( isDigit( buf[pos] ) )
- {
- auto n = decodeNumber();
- return n >= 4 &&
- pos < buf.length && '_' == buf[pos++] &&
- pos < buf.length && 'D' == buf[pos++] &&
- isDigit( buf[pos] );
- }
- else
- {
- return pos < buf.length && '_' == buf[pos++] &&
- pos < buf.length && 'D' == buf[pos++] &&
- isSymbolNameFront();
- }
- }
- void parseMangledNameArg()
- {
- debug(trace) printf( "parseMangledNameArg+\n" );
- debug(trace) scope(success) printf( "parseMangledNameArg-\n" );
- size_t n = 0;
- if ( isDigit( front ) )
- n = decodeNumber();
- parseMangledName( false, n );
- }
- /*
- TemplateInstanceName:
- Number __T LName TemplateArgs Z
- */
- void parseTemplateInstanceName(bool hasNumber) scope
- {
- debug(trace) printf( "parseTemplateInstanceName+\n" );
- debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" );
- auto sav = pos;
- auto saveBrp = brp;
- scope(failure)
- {
- pos = sav;
- brp = saveBrp;
- }
- auto n = hasNumber ? decodeNumber() : 0;
- auto beg = pos;
- match( "__T" );
- parseLName();
- put( "!(" );
- parseTemplateArgs();
- match( 'Z' );
- if ( hasNumber && pos - beg != n )
- error( "Template name length mismatch" );
- put( ')' );
- }
- bool mayBeTemplateInstanceName() scope
- {
- debug(trace) printf( "mayBeTemplateInstanceName+\n" );
- debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" );
- auto p = pos;
- scope(exit) pos = p;
- auto n = decodeNumber();
- return n >= 5 &&
- pos < buf.length && '_' == buf[pos++] &&
- pos < buf.length && '_' == buf[pos++] &&
- pos < buf.length && 'T' == buf[pos++];
- }
- /*
- SymbolName:
- LName
- TemplateInstanceName
- */
- void parseSymbolName() scope
- {
- debug(trace) printf( "parseSymbolName+\n" );
- debug(trace) scope(success) printf( "parseSymbolName-\n" );
- // LName -> Number
- // TemplateInstanceName -> Number "__T"
- switch ( front )
- {
- case '_':
- // no length encoding for templates for new mangling
- parseTemplateInstanceName(false);
- return;
- case '0': .. case '9':
- if ( mayBeTemplateInstanceName() )
- {
- auto t = len;
- try
- {
- debug(trace) printf( "may be template instance name\n" );
- parseTemplateInstanceName(true);
- return;
- }
- catch ( ParseException e )
- {
- debug(trace) printf( "not a template instance name\n" );
- len = t;
- }
- }
- goto case;
- case 'Q':
- parseLName();
- return;
- default:
- error();
- }
- }
- // parse optional function arguments as part of a symbol name, i.e without return type
- // if keepAttr, the calling convention and function attributes are not discarded, but returned
- char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope
- {
- // try to demangle a function, in case we are pointing to some function local
- auto prevpos = pos;
- auto prevlen = len;
- auto prevbrp = brp;
- char[] attr;
- try
- {
- if ( 'M' == front )
- {
- // do not emit "needs this"
- popFront();
- parseModifier();
- }
- if ( isCallConvention( front ) )
- {
- // we don't want calling convention and attributes in the qualified name
- parseCallConvention();
- parseFuncAttr();
- if ( keepAttr )
- {
- attr = dst[prevlen .. len];
- }
- else
- {
- len = prevlen;
- }
- put( '(' );
- parseFuncArguments();
- put( ')' );
- }
- }
- catch ( ParseException )
- {
- // not part of a qualified name, so back up
- pos = prevpos;
- len = prevlen;
- brp = prevbrp;
- attr = null;
- }
- return attr;
- }
- /*
- QualifiedName:
- SymbolName
- SymbolName QualifiedName
- */
- char[] parseQualifiedName() return scope
- {
- debug(trace) printf( "parseQualifiedName+\n" );
- debug(trace) scope(success) printf( "parseQualifiedName-\n" );
- size_t beg = len;
- size_t n = 0;
- do
- {
- if ( n++ )
- put( '.' );
- parseSymbolName();
- parseFunctionTypeNoReturn();
- } while ( isSymbolNameFront() );
- return dst[beg .. len];
- }
- /*
- MangledName:
- _D QualifiedName Type
- _D QualifiedName M Type
- */
- void parseMangledName( bool displayType, size_t n = 0 ) scope
- {
- debug(trace) printf( "parseMangledName+\n" );
- debug(trace) scope(success) printf( "parseMangledName-\n" );
- char[] name = null;
- auto end = pos + n;
- eat( '_' );
- match( 'D' );
- do
- {
- size_t beg = len;
- size_t nameEnd = len;
- char[] attr;
- do
- {
- if ( attr )
- remove( attr ); // dump attributes of parent symbols
- if ( beg != len )
- put( '.' );
- parseSymbolName();
- nameEnd = len;
- attr = parseFunctionTypeNoReturn( displayType );
- } while ( isSymbolNameFront() );
- if ( displayType )
- {
- attr = shift( attr );
- nameEnd = len - attr.length; // name includes function arguments
- }
- name = dst[beg .. nameEnd];
- debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr );
- if ( 'M' == front )
- popFront(); // has 'this' pointer
- auto lastlen = len;
- auto type = parseType();
- if ( displayType )
- {
- if ( type.length )
- put( ' ' );
- // sort (name,attr,type) -> (attr,type,name)
- shift( name );
- }
- else
- {
- // remove type
- assert( attr.length == 0 );
- len = lastlen;
- }
- if ( pos >= buf.length || (n != 0 && pos >= end) )
- return;
- switch ( front )
- {
- case 'T': // terminators when used as template alias parameter
- case 'V':
- case 'S':
- case 'Z':
- return;
- default:
- }
- put( '.' );
- } while ( true );
- }
- void parseMangledName()
- {
- parseMangledName( AddType.yes == addType );
- }
- char[] copyInput() return scope
- {
- if (dst.length < buf.length)
- dst.length = buf.length;
- char[] r = dst[0 .. buf.length];
- r[] = buf[];
- return r;
- }
- char[] doDemangle(alias FUNC)() return scope
- {
- while ( true )
- {
- try
- {
- debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
- FUNC();
- return dst[0 .. len];
- }
- catch ( OverflowException e )
- {
- debug(trace) printf( "overflow... restarting\n" );
- auto a = minBufSize;
- auto b = 2 * dst.length;
- auto newsz = a < b ? b : a;
- debug(info) printf( "growing dst to %lu bytes\n", newsz );
- dst.length = newsz;
- pos = len = brp = 0;
- continue;
- }
- catch ( ParseException e )
- {
- debug(info)
- {
- auto msg = e.toString();
- printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
- }
- return copyInput();
- }
- catch ( Exception e )
- {
- assert( false ); // no other exceptions thrown
- }
- }
- }
- char[] demangleName() nothrow
- {
- return doDemangle!parseMangledName();
- }
- char[] demangleType() nothrow
- {
- return doDemangle!parseType();
- }
- }
- /**
- * Demangles D mangled names. If it is not a D mangled name, it returns its
- * argument name.
- *
- * Params:
- * buf = The string to demangle.
- * dst = An optional destination buffer.
- *
- * Returns:
- * The demangled name or the original string if the name is not a mangled D
- * name.
- */
- char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe
- {
- auto d = Demangle!()(buf, dst);
- // fast path (avoiding throwing & catching exception) for obvious
- // non-D mangled names
- if (buf.length < 2 || !(buf[0] == 'D' || buf[0..2] == "_D"))
- return d.copyInput();
- return d.demangleName();
- }
- /**
- * Demangles a D mangled type.
- *
- * Params:
- * buf = The string to demangle.
- * dst = An optional destination buffer.
- *
- * Returns:
- * The demangled type name or the original string if the name is not a
- * mangled D type.
- */
- char[] demangleType( const(char)[] buf, char[] dst = null ) nothrow pure @safe
- {
- auto d = Demangle!()(buf, dst);
- return d.demangleType();
- }
- /**
- * reencode a mangled symbol name that might include duplicate occurrences
- * of the same identifier by replacing all but the first occurence with
- * a back reference.
- *
- * Params:
- * mangled = The mangled string representing the type
- *
- * Returns:
- * The mangled name with deduplicated identifiers
- */
- char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
- {
- static struct PrependHooks
- {
- size_t lastpos;
- char[] result;
- size_t[const(char)[]] idpos; // identifier positions
- static struct Replacement
- {
- size_t pos; // postion in original mangled string
- size_t respos; // postion in result string
- }
- Replacement [] replacements;
- pure @safe:
- size_t positionInResult(size_t pos) scope
- {
- foreach_reverse (r; replacements)
- if (pos >= r.pos)
- return r.respos + pos - r.pos;
- return pos;
- }
- alias Remangle = Demangle!(PrependHooks);
- void flushPosition(ref Remangle d) scope
- {
- if (lastpos < d.pos)
- {
- result ~= d.buf[lastpos .. d.pos];
- }
- else if (lastpos > d.pos)
- {
- // roll back to earlier position
- while (replacements.length > 0 && replacements[$-1].pos > d.pos)
- replacements = replacements[0 .. $-1];
- if (replacements.length > 0)
- result.length = replacements[$-1].respos + d.pos - replacements[$-1].pos;
- else
- result.length = d.pos;
- }
- }
- bool parseLName(scope ref Remangle d) scope
- {
- flushPosition(d);
- auto reslen = result.length;
- auto refpos = d.pos;
- if (d.front == 'Q')
- {
- size_t npos;
- {
- scope(exit) result.length = reslen; // remove all intermediate additions
- // only support identifier back references
- d.popFront();
- size_t n = d.decodeBackref();
- if (!n || n > refpos)
- d.error("invalid back reference");
- auto savepos = d.pos;
- scope(exit) d.pos = savepos;
- size_t srcpos = refpos - n;
- auto idlen = d.decodeNumber();
- if (d.pos + idlen > d.buf.length)
- d.error("invalid back reference");
- auto id = d.buf[d.pos .. d.pos + idlen];
- auto pid = id in idpos;
- if (!pid)
- d.error("invalid back reference");
- npos = positionInResult(*pid);
- }
- encodeBackref(reslen - npos);
- const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
- replacements ~= Replacement(pos, result.length);
- }
- else
- {
- auto n = d.decodeNumber();
- if (!n || n > d.buf.length || n > d.buf.length - d.pos)
- d.error("LName too shot or too long");
- auto id = d.buf[d.pos .. d.pos + n];
- d.pos += n;
- if (auto pid = id in idpos)
- {
- size_t npos = positionInResult(*pid);
- result.length = reslen;
- encodeBackref(reslen - npos);
- const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
- replacements ~= Replacement(pos, result.length);
- }
- else
- {
- idpos[id] = refpos;
- result ~= d.buf[refpos .. d.pos];
- }
- }
- lastpos = d.pos;
- return true;
- }
- char[] parseType( ref Remangle d, char[] name = null ) return scope
- {
- if (d.front != 'Q')
- return null;
- flushPosition(d);
- auto refPos = d.pos;
- d.popFront();
- auto n = d.decodeBackref();
- if (n == 0 || n > refPos)
- d.error("invalid back reference");
- size_t npos = positionInResult(refPos - n);
- size_t reslen = result.length;
- encodeBackref(reslen - npos);
- lastpos = d.pos;
- return result[reslen .. $]; // anything but null
- }
- void encodeBackref(size_t relpos) scope
- {
- result ~= 'Q';
- enum base = 26;
- size_t div = 1;
- while (relpos >= div * base)
- div *= base;
- while (div >= base)
- {
- auto dig = (relpos / div);
- result ~= cast(char)('A' + dig);
- relpos -= dig * div;
- div /= base;
- }
- result ~= cast(char)('a' + relpos);
- }
- }
- auto d = Demangle!(PrependHooks)(mangled, null);
- d.hooks = PrependHooks();
- d.mute = true; // no demangled output
- try
- {
- d.parseMangledName();
- if (d.hooks.lastpos < d.pos)
- d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
- return d.hooks.result;
- }
- catch (Exception)
- {
- // overflow exception cannot occur
- return mangled.dup;
- }
- }
- /**
- * Mangles a D symbol.
- *
- * Params:
- * T = The type of the symbol.
- * fqn = The fully qualified name of the symbol.
- * dst = An optional destination buffer.
- *
- * Returns:
- * The mangled name for a symbols of type T and the given fully
- * qualified name.
- */
- char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow
- {
- import core.internal.string : numDigits, unsignedToTempString;
- static struct DotSplitter
- {
- @safe pure nothrow:
- const(char)[] s;
- @property bool empty() const { return !s.length; }
- @property const(char)[] front() const return
- {
- immutable i = indexOfDot();
- return i == -1 ? s[0 .. $] : s[0 .. i];
- }
- void popFront() scope
- {
- immutable i = indexOfDot();
- s = i == -1 ? s[$ .. $] : s[i+1 .. $];
- }
- private ptrdiff_t indexOfDot() const scope
- {
- foreach (i, c; s) if (c == '.') return i;
- return -1;
- }
- }
- size_t len = "_D".length;
- foreach (comp; DotSplitter(fqn))
- len += numDigits(comp.length) + comp.length;
- len += T.mangleof.length;
- if (dst.length < len) dst.length = len;
- size_t i = "_D".length;
- dst[0 .. i] = "_D";
- foreach (comp; DotSplitter(fqn))
- {
- const ndigits = numDigits(comp.length);
- unsignedToTempString(comp.length, dst[i .. i + ndigits]);
- i += ndigits;
- dst[i .. i + comp.length] = comp[];
- i += comp.length;
- }
- dst[i .. i + T.mangleof.length] = T.mangleof[];
- i += T.mangleof.length;
- static if (hasTypeBackRef)
- return reencodeMangled(dst[0 .. i]);
- else
- return dst[0 .. i];
- }
- ///
- @safe pure nothrow unittest
- {
- assert(mangle!int("a.b") == "_D1a1bi");
- assert(mangle!(char[])("test.foo") == "_D4test3fooAa");
- assert(mangle!(int function(int))("a.b") == "_D1a1bPFiZi");
- }
- @safe pure nothrow unittest
- {
- static assert(mangle!int("a.b") == "_D1a1bi");
- auto buf = new char[](10);
- buf = mangle!int("a.b", buf);
- assert(buf == "_D1a1bi");
- buf = mangle!(char[])("test.foo", buf);
- assert(buf == "_D4test3fooAa");
- buf = mangle!(real delegate(int))("modµ.dg");
- assert(buf == "_D5modµ2dgDFiZe", buf);
- }
- /**
- * Mangles a D function.
- *
- * Params:
- * T = function pointer type.
- * fqn = The fully qualified name of the symbol.
- * dst = An optional destination buffer.
- *
- * Returns:
- * The mangled name for a function with function pointer type T and
- * the given fully qualified name.
- */
- char[] mangleFunc(T:FT*, FT)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow if (is(FT == function))
- {
- static if (isExternD!FT)
- {
- return mangle!FT(fqn, dst);
- }
- else static if (hasPlainMangling!FT)
- {
- dst.length = fqn.length;
- dst[] = fqn[];
- return dst;
- }
- else static if (isExternCPP!FT)
- {
- static assert(0, "Can't mangle extern(C++) functions.");
- }
- else
- {
- static assert(0, "Can't mangle function with unknown linkage ("~FT.stringof~").");
- }
- }
- private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi";
- @safe pure nothrow unittest
- {
- assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
- static if (hasTypeBackRef)
- {
- assert(mangleFunc!(int function(Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQsZi");
- assert(mangleFunc!(int function(Object, Object))("object.Object.opEquals") == "_D6object6Object8opEqualsFCQsQdZi");
- }
- else
- {
- auto mngl = mangleFunc!(int function(Object))("object.Object.opEquals");
- assert(mngl == "_D6object6Object8opEqualsFC6ObjectZi");
- auto remngl = reencodeMangled(mngl);
- assert(remngl == "_D6object6Object8opEqualsFCQsZi");
- }
- // trigger back tracking with ambiguity on '__T', template or identifier
- assert(reencodeMangled("_D3std4conv4conv7__T3std4convi") == "_D3std4convQf7__T3stdQpi");
- }
- @safe pure nothrow unittest
- {
- int function(lazy int[], ...) fp;
- assert(mangle!(typeof(fp))("demangle.test") == "_D8demangle4testPFLAiYi");
- assert(mangle!(typeof(*fp))("demangle.test") == "_D8demangle4testFLAiYi");
- }
- private template isExternD(FT) if (is(FT == function))
- {
- enum isExternD = __traits(getLinkage, FT) == "D";
- }
- private template isExternCPP(FT) if (is(FT == function))
- {
- enum isExternCPP = __traits(getLinkage, FT) == "C++";
- }
- private template hasPlainMangling(FT) if (is(FT == function))
- {
- enum lnk = __traits(getLinkage, FT);
- // C || Windows
- enum hasPlainMangling = lnk == "C" || lnk == "Windows" || lnk == "System";
- }
- @safe pure nothrow unittest
- {
- static extern(D) void fooD();
- static extern(C) void fooC();
- static extern(Windows) void fooW();
- static extern(C++) void fooCPP();
- bool check(FT)(bool isD, bool isCPP, bool isPlain)
- {
- return isExternD!FT == isD && isExternCPP!FT == isCPP &&
- hasPlainMangling!FT == isPlain;
- }
- static assert(check!(typeof(fooD))(true, false, false));
- static assert(check!(typeof(fooC))(false, false, true));
- static assert(check!(typeof(fooW))(false, false, true));
- static assert(check!(typeof(fooCPP))(false, true, false));
- static assert(__traits(compiles, mangleFunc!(typeof(&fooD))("")));
- static assert(__traits(compiles, mangleFunc!(typeof(&fooC))("")));
- static assert(__traits(compiles, mangleFunc!(typeof(&fooW))("")));
- static assert(!__traits(compiles, mangleFunc!(typeof(&fooCPP))("")));
- }
- /***
- * C name mangling is done by adding a prefix on some platforms.
- */
- version (Win32)
- enum string cPrefix = "_";
- else version (Darwin)
- enum string cPrefix = "_";
- else
- enum string cPrefix = "";
- @safe pure nothrow unittest
- {
- immutable string[2][] table =
- [
- ["printf", "printf"],
- ["_foo", "_foo"],
- ["_D88", "_D88"],
- ["_D3fooQeFIAyaZv", "void foo.foo(in immutable(char)[])" ],
- ["_D3barQeFIKAyaZv", "void bar.bar(in ref immutable(char)[])" ],
- ["_D4test3fooAa", "char[] test.foo"],
- ["_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])"],
- ["_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(Object)"],
- ["_D4test2dgDFiYd", "double delegate(int, ...) test.dg"],
- ["_D4test2dgDxFNfiYd", "double delegate(int, ...) @safe const test.dg"],
- //["_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", ""],
- //["_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", ""],
- ["_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(\"abc\"w, \"def\"d).x"],
- ["_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy Object, lazy int delegate(lazy int))"],
- ["_D8demangle4testFAiXi", "int demangle.test(int[]...)"],
- ["_D8demangle4testFAiYi", "int demangle.test(int[], ...)"],
- ["_D8demangle4testFLAiXi", "int demangle.test(lazy int[]...)"],
- ["_D8demangle4testFLAiYi", "int demangle.test(lazy int[], ...)"],
- ["_D6plugin8generateFiiZAya", "immutable(char)[] plugin.generate(int, int)"],
- ["_D6plugin8generateFiiZAxa", "const(char)[] plugin.generate(int, int)"],
- ["_D6plugin8generateFiiZAOa", "shared(char)[] plugin.generate(int, int)"],
- ["_D8demangle3fnAFZ3fnBMFZv", "void demangle.fnA().fnB()"],
- ["_D8demangle4mainFZ1S3fnCMFZv", "void demangle.main().S.fnC()"],
- ["_D8demangle4mainFZ1S3fnDMFZv", "void demangle.main().S.fnD()"],
- ["_D8demangle20__T2fnVAiA4i1i2i3i4Z2fnFZv", "void demangle.fn!([1, 2, 3, 4]).fn()"],
- ["_D8demangle10__T2fnVi1Z2fnFZv", "void demangle.fn!(1).fn()"],
- ["_D8demangle26__T2fnVS8demangle1SS2i1i2Z2fnFZv", "void demangle.fn!(demangle.S(1, 2)).fn()"],
- ["_D8demangle13__T2fnVeeNANZ2fnFZv", "void demangle.fn!(real.nan).fn()"],
- ["_D8demangle14__T2fnVeeNINFZ2fnFZv", "void demangle.fn!(-real.infinity).fn()"],
- ["_D8demangle13__T2fnVeeINFZ2fnFZv", "void demangle.fn!(real.infinity).fn()"],
- ["_D8demangle21__T2fnVHiiA2i1i2i3i4Z2fnFZv", "void demangle.fn!([1:2, 3:4]).fn()"],
- ["_D8demangle2fnFNgiZNgi", "inout(int) demangle.fn(inout(int))"],
- ["_D8demangle29__T2fnVa97Va9Va0Vu257Vw65537Z2fnFZv", "void demangle.fn!('a', '\\t', \\x00, '\\u0101', '\\U00010001').fn()"],
- ["_D2gc11gctemplates56__T8mkBitmapTS3std5range13__T4iotaTiTiZ4iotaFiiZ6ResultZ8mkBitmapFNbNiNfPmmZv",
- "nothrow @nogc @safe void gc.gctemplates.mkBitmap!(std.range.iota!(int, int).iota(int, int).Result).mkBitmap(ulong*, ulong)"],
- ["_D8serenity9persister6Sqlite69__T15SqlitePersisterTS8serenity9persister6Sqlite11__unittest6FZ4TestZ15SqlitePersister12__T7opIndexZ7opIndexMFmZS8serenity9persister6Sqlite11__unittest6FZ4Test",
- "serenity.persister.Sqlite.__unittest6().Test serenity.persister.Sqlite.SqlitePersister!(serenity.persister.Sqlite.__unittest6().Test).SqlitePersister.opIndex!().opIndex(ulong)"],
- ["_D8bug100274mainFZ5localMFZi","int bug10027.main().local()"],
- ["_D8demangle4testFNhG16gZv", "void demangle.test(__vector(byte[16]))"],
- ["_D8demangle4testFNhG8sZv", "void demangle.test(__vector(short[8]))"],
- ["_D8demangle4testFNhG4iZv", "void demangle.test(__vector(int[4]))"],
- ["_D8demangle4testFNhG2lZv", "void demangle.test(__vector(long[2]))"],
- ["_D8demangle4testFNhG4fZv", "void demangle.test(__vector(float[4]))"],
- ["_D8demangle4testFNhG2dZv", "void demangle.test(__vector(double[2]))"],
- ["_D8demangle4testFNhG4fNhG4fZv", "void demangle.test(__vector(float[4]), __vector(float[4]))"],
- ["_D8bug1119234__T3fooS23_D8bug111924mainFZ3bariZ3fooMFZv","void bug11192.foo!(bug11192.main().bar).foo()"],
- ["_D13libd_demangle12__ModuleInfoZ", "libd_demangle.__ModuleInfo"],
- ["_D15TypeInfo_Struct6__vtblZ", "TypeInfo_Struct.__vtbl"],
- ["_D3std5stdio12__ModuleInfoZ", "std.stdio.__ModuleInfo"],
- ["_D3std6traits15__T8DemangleTkZ8Demangle6__initZ", "std.traits.Demangle!(uint).Demangle.__init"],
- ["_D3foo3Bar7__ClassZ", "foo.Bar.__Class"],
- ["_D3foo3Bar6__vtblZ", "foo.Bar.__vtbl"],
- ["_D3foo3Bar11__interfaceZ", "foo.Bar.__interface"],
- ["_D3foo7__arrayZ", "foo.__array"],
- ["_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
- ["_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
- ["_D4test22__T4funcVAyaa3_610a62Z4funcFNaNbNiNmNfZAya", `pure nothrow @nogc @live @safe immutable(char)[] test.func!("a\x0ab").func()`],
- ["_D3foo3barFzkZzi", "cent foo.bar(ucent)"],
- ["_D5bug145Class3fooMFNlZPv", "scope void* bug14.Class.foo()"],
- ["_D5bug145Class3barMFNjZPv", "return void* bug14.Class.bar()"],
- ["_D5bug143fooFMPvZPv", "void* bug14.foo(scope void*)"],
- ["_D5bug143barFMNkPvZPv", "void* bug14.bar(scope return void*)"],
- ["_D3std5range15__T4iotaTtTtTtZ4iotaFtttZ6Result7opIndexMNgFNaNbNiNfmZNgt",
- "inout pure nothrow @nogc @safe inout(ushort) std.range.iota!(ushort, ushort, ushort).iota(ushort, ushort, ushort).Result.opIndex(ulong)"],
- ["_D3std6format77__T6getNthVAyaa13_696e7465676572207769647468S233std6traits10isIntegralTiTkTkZ6getNthFNaNfkkkZi",
- "pure @safe int std.format.getNth!(\"integer width\", std.traits.isIntegral, int, uint, uint).getNth(uint, uint, uint)"],
- ["_D3std11parallelism42__T16RoundRobinBufferTDFKAaZvTDxFNaNdNeZbZ16RoundRobinBuffer5primeMFZv",
- "void std.parallelism.RoundRobinBuffer!(void delegate(ref char[]), bool delegate() pure @property @trusted const).RoundRobinBuffer.prime()"],
- ["_D6mangle__T8fun21753VSQv6S21753S1f_DQBj10__lambda71MFNaNbNiNfZvZQCbQp",
- "void function() pure nothrow @nogc @safe mangle.fun21753!(mangle.S21753(mangle.__lambda71())).fun21753"],
- // Lname '0'
- ["_D3std9algorithm9iteration__T9MapResultSQBmQBlQBe005stripTAAyaZQBi7opSliceMFNaNbNiNfmmZSQDiQDhQDa__TQCtSQDyQDxQDq00QCmTQCjZQDq",
- "pure nothrow @nogc @safe std.algorithm.iteration.MapResult!(std.algorithm.iteration.__anonymous.strip, "
- ~"immutable(char)[][]).MapResult std.algorithm.iteration.MapResult!(std.algorithm.iteration.strip, immutable(char)[][]).MapResult.opSlice(ulong, ulong)"],
- // back references
- ["_D4core4stdc5errnoQgFZi", "int core.stdc.errno.errno()"], // identifier back reference
- ["_D4testFS10structnameQnZb", "bool test(structname, structname)"], // type back reference
- ["_D3std11parallelism__T4TaskS8unittest3cmpTAyaTQeZQBb6__dtorMFNfZv",
- "@safe void std.parallelism.Task!(unittest.cmp, immutable(char)[], immutable(char)[]).Task.__dtor()"],
- // 1.s.s.foo from https://issues.dlang.org/show_bug.cgi?id=15831
- ["_D13testexpansion44__T1sTS13testexpansion8__T1sTiZ1sFiZ6ResultZ1sFS13testexpansion8__T1sTiZ1sFiZ6ResultZ6Result3fooMFNaNfZv",
- "pure @safe void testexpansion.s!(testexpansion.s!(int).s(int).Result).s(testexpansion.s!(int).s(int).Result).Result.foo()"],
- ["_D13testexpansion__T1sTSQw__TQjTiZQoFiZ6ResultZQBbFQBcZQq3fooMFNaNfZv",
- "pure @safe void testexpansion.s!(testexpansion.s!(int).s(int).Result).s(testexpansion.s!(int).s(int).Result).Result.foo()"],
- // formerly ambiguous on 'V', template value argument or pascal function
- // pascal functions have now been removed (in v2.095.0)
- ["_D3std4conv__T7enumRepTyAaTEQBa12experimental9allocator15building_blocks15stats_collector7OptionsVQCti64ZQDnyQDh",
- "immutable(char[]) std.conv.enumRep!(immutable(char[]), std.experimental.allocator.building_blocks.stats_collector.Options, 64).enumRep"],
- // symbol back reference to location with symbol back reference
- ["_D3std12experimental9allocator6common__T10reallocateTSQCaQBzQBo15building_blocks17kernighan_ritchie__T8KRRegionTSQEhQEgQDvQCh14null_allocator13NullAllocatorZQCdZQErFNaNbNiKQEpKAvmZb",
- "pure nothrow @nogc bool std.experimental.allocator.common.reallocate!(std.experimental.allocator.building_blocks.kernighan_ritchie.KRRegion!("
- ~"std.experimental.allocator.building_blocks.null_allocator.NullAllocator).KRRegion).reallocate(ref "
- ~"std.experimental.allocator.building_blocks.kernighan_ritchie.KRRegion!(std.experimental.allocator.building_blocks.null_allocator.NullAllocator).KRRegion, ref void[], ulong)"],
- ["_D3std9exception__T11doesPointToTASQBh5regex8internal2ir10NamedGroupTQBkTvZQCeFNaNbNiNeKxASQDlQCeQCbQBvQBvKxQtZb",
- "pure nothrow @nogc @trusted bool std.exception.doesPointTo!(std.regex.internal.ir.NamedGroup[], "
- ~"std.regex.internal.ir.NamedGroup[], void).doesPointTo(ref const(std.regex.internal.ir.NamedGroup[]), ref const(std.regex.internal.ir.NamedGroup[]))"],
- ["_D3std9algorithm9iteration__T14SplitterResultS_DQBu3uni7isWhiteFNaNbNiNfwZbTAyaZQBz9__xtoHashFNbNeKxSQDvQDuQDn__TQDgS_DQEnQCtQCsQCnTQCeZQEdZm",
- "nothrow @trusted ulong std.algorithm.iteration.SplitterResult!(std.uni.isWhite(dchar), immutable(char)[]).SplitterResult."
- ~"__xtoHash(ref const(std.algorithm.iteration.SplitterResult!(std.uni.isWhite, immutable(char)[]).SplitterResult))"],
- ["_D3std8typecons__T7TypedefTCQBaQz19__unittestL6513_208FNfZ7MyClassVQBonVAyanZQCh6__ctorMFNaNbNcNiNfQCuZSQDyQDx__TQDrTQDmVQDqnVQCcnZQEj",
- "pure nothrow ref @nogc @safe std.typecons.Typedef!(std.typecons.__unittestL6513_208().MyClass, null, null).Typedef "
- ~"std.typecons.Typedef!(std.typecons.__unittestL6513_208().MyClass, null, null).Typedef.__ctor(std.typecons.__unittestL6513_208().MyClass)"],
- ["_D3std6getopt__TQkTAyaTDFNaNbNiNfQoZvTQtTDQsZQBnFNfKAQBiQBlQBkQBrQyZSQCpQCo12GetoptResult",
- "@safe std.getopt.GetoptResult std.getopt.getopt!(immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe, "
- ~"immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe)."
- ~"getopt(ref immutable(char)[][], immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe, "
- ~"immutable(char)[], void delegate(immutable(char)[]) pure nothrow @nogc @safe)"],
- ["_D3std5regex8internal9kickstart__T7ShiftOrTaZQl11ShiftThread__T3setS_DQCqQCpQCmQCg__TQBzTaZQCfQBv10setInvMaskMFNaNbNiNfkkZvZQCjMFNaNfwZv",
- "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)"],
- ["_D3std5stdio4File__T8lockImplX10LockFileExTykZQBaMFmmykZi", // C function as template alias parameter
- "int std.stdio.File.lockImpl!(LockFileEx, immutable(uint)).lockImpl(ulong, ulong, immutable(uint))"],
- // back reference for type in template AA parameter value
- ["_D3std9algorithm9iteration__T12FilterResultSQBq8typecons__T5TupleTiVAyaa1_61TiVQla1_62TiVQva1_63ZQBm__T6renameVHiQBtA2i0a1_63i2a1_61ZQBeMFNcZ9__lambda1TAiZQEw9__xtoHashFNbNeKxSQGsQGrQGk__TQGdSQHiQFs__TQFmTiVQFja1_61TiVQFua1_62TiVQGfa1_63ZQGx__TQFlVQFhA2i0a1_63i2a1_61ZQGjMFNcZQFfTQEyZQJvZm",
- `nothrow @trusted ulong std.algorithm.iteration.FilterResult!(std.typecons.Tuple!(int, "a", int, "b", int, "c").`
- ~`Tuple.rename!([0:"c", 2:"a"]).rename().__lambda1, int[]).FilterResult.__xtoHash(ref const(std.algorithm.iteration.`
- ~`FilterResult!(std.typecons.Tuple!(int, "a", int, "b", int, "c").Tuple.rename!([0:"c", 2:"a"]).rename().__lambda1, int[]).FilterResult))`],
- ["_D4test4rrs1FKPiZv", "void test.rrs1(ref int*)"],
- ["_D4test4rrs1FMNkJPiZv", "void test.rrs1(scope return out int*)"],
- ["_D4test4rrs1FMNkKPiZv", "void test.rrs1(scope return ref int*)"],
- ["_D4test4rrs1FNkJPiZv", "void test.rrs1(return out int*)"],
- ["_D4test4rrs1FNkKPiZv", "void test.rrs1(return ref int*)"],
- ["_D4test4rrs1FNkMJPiZv", "void test.rrs1(return scope out int*)"],
- ["_D4test4rrs1FNkMKPiZv", "void test.rrs1(return scope ref int*)"],
- ["_D4test4rrs1FNkMPiZv", "void test.rrs1(return scope int*)"],
- ];
- template staticIota(int x)
- {
- template Seq(T...){ alias Seq = T; }
- static if (x == 0)
- alias staticIota = Seq!();
- else
- alias staticIota = Seq!(staticIota!(x - 1), x - 1);
- }
- foreach ( i, name; table )
- {
- auto r = demangle( name[0] );
- assert( r == name[1],
- "demangled `" ~ name[0] ~ "` as `" ~ r ~ "` but expected `" ~ name[1] ~ "`");
- }
- foreach ( i; staticIota!(table.length) )
- {
- enum r = demangle( table[i][0] );
- static assert( r == table[i][1],
- "demangled `" ~ table[i][0] ~ "` as `" ~ r ~ "` but expected `" ~ table[i][1] ~ "`");
- }
- {
- // https://issues.dlang.org/show_bug.cgi?id=18531
- auto symbol = `_D3std3uni__T6toCaseS_DQvQt12toLowerIndexFNaNbNiNewZtVii1043S_DQCjQCi10toLowerTabFNaNbNiNemZwSQDo5ascii7toLowerTAyaZQDzFNaNeQmZ14__foreachbody2MFNaNeKmKwZ14__foreachbody3MFNaNeKwZi`;
- 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)`;
- auto dst = new char[200];
- auto ret = demangle( symbol, dst);
- assert( ret == demangled );
- }
- }
- unittest
- {
- // https://issues.dlang.org/show_bug.cgi?id=18300
- string s = demangle.mangleof;
- foreach (i; 1..77)
- {
- char[] buf = new char[i];
- auto ds = demangle(s, buf);
- assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[])" ||
- ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[])");
- }
- }
- unittest
- {
- // https://issues.dlang.org/show_bug.cgi?id=18300
- string s = "_D1";
- string expected = "int ";
- foreach (_; 0..10_000)
- {
- s ~= "a1";
- expected ~= "a.";
- }
- s ~= "FiZi";
- expected ~= "F";
- assert(s.demangle == expected);
- }
- // https://issues.dlang.org/show_bug.cgi?id=22235
- unittest
- {
- enum parent = __MODULE__ ~ '.' ~ __traits(identifier, __traits(parent, {}));
- static noreturn abort() { assert(false); }
- assert(demangle(abort.mangleof) == "pure nothrow @nogc @safe noreturn " ~ parent ~ "().abort()");
- static void accept(noreturn) {}
- assert(demangle(accept.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().accept(noreturn)");
- static void templ(T)(T, T) {}
- assert(demangle(templ!noreturn.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().templ!(noreturn).templ(noreturn, noreturn)");
- static struct S(T) {}
- static void aggr(S!noreturn) { assert(0); }
- assert(demangle(aggr.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().aggr(" ~ parent ~ "().S!(noreturn).S)");
- }
- /*
- *
- */
- string decodeDmdString( const(char)[] ln, ref size_t p ) nothrow pure @safe
- {
- string s;
- uint zlen, zpos;
- // decompress symbol
- while ( p < ln.length )
- {
- int ch = cast(ubyte) ln[p++];
- if ( (ch & 0xc0) == 0xc0 )
- {
- zlen = (ch & 0x7) + 1;
- zpos = ((ch >> 3) & 7) + 1; // + zlen;
- if ( zpos > s.length )
- break;
- s ~= s[$ - zpos .. $ - zpos + zlen];
- }
- else if ( ch >= 0x80 )
- {
- if ( p >= ln.length )
- break;
- int ch2 = cast(ubyte) ln[p++];
- zlen = (ch2 & 0x7f) | ((ch & 0x38) << 4);
- if ( p >= ln.length )
- break;
- int ch3 = cast(ubyte) ln[p++];
- zpos = (ch3 & 0x7f) | ((ch & 7) << 7);
- if ( zpos > s.length )
- break;
- s ~= s[$ - zpos .. $ - zpos + zlen];
- }
- else if ( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' )
- s ~= cast(char) ch;
- else
- {
- p--;
- break;
- }
- }
- return s;
- }
- // locally purified for internal use here only
- extern (C) private
- {
- pure @trusted @nogc nothrow pragma(mangle, "fakePureReprintReal") void pureReprintReal(char[] nptr);
- void fakePureReprintReal(char[] nptr)
- {
- import core.stdc.stdlib : strtold;
- import core.stdc.stdio : snprintf;
- import core.stdc.errno : errno;
- const err = errno;
- real val = strtold(nptr.ptr, null);
- snprintf(nptr.ptr, nptr.length, "%#Lg", val);
- errno = err;
- }
- }
|