@@ -24,7 +24,14 @@ else version (WatchOS)
2424debug (trace) import core.stdc.stdio : printf;
2525debug (info) import core.stdc.stdio : printf;
2626
27- private struct Demangle
27+ private struct NoHooks
28+ {
29+ // supported hooks
30+ // static bool parseLName(ref Demangle);
31+ // static char[] parseType(ref Demangle, char[])
32+ }
33+
34+ private struct Demangle (Hooks = NoHooks)
2835{
2936 // NOTE: This implementation currently only works with mangled function
3037 // names as they exist in an object file. Type names mangled via
7178 size_t brp = 0 ; // current back reference pos
7279 AddType addType = AddType.yes;
7380 bool mute = false ;
81+ Hooks hooks;
7482
7583 static class ParseException : Exception
7684 {
@@ -538,6 +546,10 @@ pure:
538546 debug (trace) printf( " parseLName+\n " );
539547 debug (trace) scope (success) printf( " parseLName-\n " );
540548
549+ static if (__traits(hasMember, Hooks, " parseLName" ))
550+ if (hooks.parseLName(this ))
551+ return ;
552+
541553 if ( front == ' Q' )
542554 {
543555 // back reference to LName
@@ -771,6 +783,10 @@ pure:
771783 " dchar" , // w
772784 ];
773785
786+ static if (__traits(hasMember, Hooks, " parseType" ))
787+ if (auto n = hooks.parseType(this , name))
788+ return n;
789+
774790 debug (trace) printf( " parseType+\n " );
775791 debug (trace) scope (success) printf( " parseType-\n " );
776792 auto beg = len;
@@ -1962,7 +1978,7 @@ pure:
19621978char [] demangle ( const (char )[] buf, char [] dst = null )
19631979{
19641980 // return Demangle(buf, dst)();
1965- auto d = Demangle(buf, dst);
1981+ auto d = Demangle! () (buf, dst);
19661982 return d.demangleName();
19671983}
19681984
@@ -1980,10 +1996,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
19801996*/
19811997char [] demangleType ( const (char )[] buf, char [] dst = null )
19821998{
1983- auto d = Demangle(buf, dst);
1999+ auto d = Demangle! () (buf, dst);
19842000 return d.demangleType();
19852001}
19862002
2003+ /**
2004+ * reencode a mangled symbol name that might include duplicate occurrences
2005+ * of the same identifier by replacing all but the first occurence with
2006+ * a back reference.
2007+ *
2008+ * Params:
2009+ * mangled = The mangled string representing the type
2010+ *
2011+ * Returns:
2012+ * The mangled name with deduplicated identifiers
2013+ */
2014+ char [] reencodeMangled (const (char )[] mangled) nothrow pure @safe
2015+ {
2016+ static struct PrependHooks
2017+ {
2018+ size_t lastpos;
2019+ char [] result;
2020+ size_t [const (char )[]] idpos; // identifier positions
2021+
2022+ static struct Replacement
2023+ {
2024+ size_t pos; // postion in original mangled string
2025+ size_t respos; // postion in result string
2026+ }
2027+ Replacement [] replacements;
2028+
2029+ pure :
2030+ size_t positionInResult (size_t pos)
2031+ {
2032+ foreach_reverse (r; replacements)
2033+ if (pos >= r.pos)
2034+ return r.respos + pos - r.pos;
2035+ return pos;
2036+ }
2037+
2038+ alias Remangle = Demangle! (PrependHooks);
2039+
2040+ bool parseLName (ref Remangle d)
2041+ {
2042+ if (lastpos < d.pos)
2043+ result ~= d.buf[lastpos .. d.pos];
2044+ else if (lastpos > d.pos)
2045+ {
2046+ // todo: roll back to earlier position
2047+ }
2048+
2049+ auto reslen = result.length;
2050+ auto refpos = d.pos;
2051+ if (d.front == ' Q' )
2052+ {
2053+ size_t npos;
2054+ {
2055+ scope (exit) result.length = reslen; // remove all intermediate additions
2056+ // only support identifier back references
2057+ d.popFront();
2058+ size_t n = d.decodeNumber! ' A' ();
2059+ if (! n || n > refpos)
2060+ d.error(" invalid back reference" );
2061+
2062+ auto savepos = d.pos;
2063+ scope (exit) d.pos = savepos;
2064+ size_t srcpos = refpos - n;
2065+
2066+ auto idlen = d.decodeNumber();
2067+ if (d.pos + idlen > d.buf.length)
2068+ d.error(" invalid back reference" );
2069+ auto id = d.buf[d.pos .. d.pos + idlen];
2070+ auto pid = id in idpos;
2071+ if (! pid)
2072+ d.error(" invalid back reference" );
2073+ npos = positionInResult(* pid);
2074+ }
2075+ encodeBackref(reslen - npos, ' A' );
2076+ replacements ~= Replacement(d.pos, result.length);
2077+ }
2078+ else
2079+ {
2080+ auto n = d.decodeNumber();
2081+ if (! n || n > d.buf.length || n > d.buf.length - d.pos)
2082+ d.error(" LName too shot or too long" );
2083+ auto id = d.buf[d.pos .. d.pos + n];
2084+ d.pos += n;
2085+ if (auto pid = id in idpos)
2086+ {
2087+ size_t npos = positionInResult(* pid);
2088+ result.length = reslen;
2089+ encodeBackref(reslen - npos, ' A' );
2090+ replacements ~= Replacement(d.pos, result.length);
2091+ }
2092+ else
2093+ {
2094+ idpos[id] = refpos;
2095+ result ~= d.buf[refpos .. d.pos];
2096+ }
2097+ }
2098+ lastpos = d.pos;
2099+ return true ;
2100+ }
2101+
2102+ char [] parseType ( ref Remangle d, char [] name = null )
2103+ {
2104+ if (d.front != ' Q' )
2105+ return null ;
2106+
2107+ if (lastpos < d.pos)
2108+ result ~= d.buf[lastpos .. d.pos];
2109+ else if (lastpos > d.pos)
2110+ {
2111+ // todo: roll back to earlier position
2112+ }
2113+
2114+ auto refPos = d.pos;
2115+ d.popFront();
2116+ auto n = d.decodeNumber! ' a' ();
2117+ if (n == 0 || n > refPos)
2118+ d.error(" invalid back reference" );
2119+
2120+ size_t npos = positionInResult(refPos - n);
2121+ size_t reslen = result.length;
2122+ encodeBackref(reslen - npos, ' a' );
2123+
2124+ lastpos = d.pos;
2125+ return result[reslen .. $]; // anything but null
2126+ }
2127+
2128+ void encodeBackref (size_t relpos, char lastDigitBase)
2129+ {
2130+ result ~= ' Q' ;
2131+ size_t div = 1 ;
2132+ while (relpos >= div * 10 )
2133+ div *= 10 ;
2134+ while (div >= 10 )
2135+ {
2136+ auto dig = (relpos / div);
2137+ result ~= cast (char )(' 0' + dig);
2138+ relpos -= dig * div;
2139+ div /= 10 ;
2140+ }
2141+ result ~= cast (char )(lastDigitBase + relpos);
2142+ }
2143+ }
2144+
2145+ auto d = Demangle! (PrependHooks)(mangled, null );
2146+ d.hooks = PrependHooks();
2147+ d.mute = true ; // no demangled output
2148+ try
2149+ {
2150+ () @trusted { d.parseMangledName(); }();
2151+ if (d.hooks.lastpos < d.pos)
2152+ d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
2153+ return d.hooks.result;
2154+ }
2155+ catch (Exception )
2156+ {
2157+ // overflow exception cannot occur
2158+ return mangled.dup ;
2159+ }
2160+ }
19872161
19882162/**
19892163 * Mangles a D symbol.
@@ -2045,7 +2219,11 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
20452219 }
20462220 dst[i .. i + T.mangleof.length] = T.mangleof[];
20472221 i += T.mangleof.length;
2048- return dst[0 .. i];
2222+
2223+ static if (hasTypeBackRef)
2224+ return reencodeMangled (dst[0 .. i]);
2225+ else
2226+ return dst[0 .. i];
20492227}
20502228
20512229
@@ -2105,12 +2283,19 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
21052283 }
21062284}
21072285
2286+ private enum hasTypeBackRef = (int function (void ** ,void ** )).mangleof[$- 4 .. $] == " QdZi" ;
21082287
21092288// /
21102289unittest
21112290{
21122291 assert (mangleFunc! (int function (int ))(" a.b" ) == " _D1a1bFiZi" );
2113- assert (mangleFunc! (int function (Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFC6ObjectZi" );
2292+ static if (hasTypeBackRef)
2293+ {
2294+ assert (mangleFunc! (int function (Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFCQ1IZi" );
2295+ assert (mangleFunc! (int function (Object , Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFCQ1IQeZi" );
2296+ }
2297+ else
2298+ assert (mangleFunc! (int function (Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFC6ObjectZi" );
21142299}
21152300
21162301unittest
@@ -2343,7 +2528,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
23432528 break ;
23442529 s ~= s[$ - zpos .. $ - zpos + zlen];
23452530 }
2346- else if ( Demangle.isAlpha(cast (char )ch) || Demangle.isDigit(cast (char )ch) || ch == ' _' )
2531+ else if ( Demangle! () .isAlpha(cast (char )ch) || Demangle! () .isDigit(cast (char )ch) || ch == ' _' )
23472532 s ~= cast (char ) ch;
23482533 else
23492534 {
0 commit comments