@@ -24,7 +24,9 @@ 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+ private struct Demangle (Hooks = NoHooks)
2830{
2931 // NOTE: This implementation currently only works with mangled function
3032 // names as they exist in an object file. Type names mangled via
7173 size_t brp = 0 ; // current back reference pos
7274 AddType addType = AddType.yes;
7375 bool mute = false ;
76+ Hooks hooks;
7477
7578 static class ParseException : Exception
7679 {
@@ -540,6 +543,10 @@ pure:
540543 debug (trace) printf( " parseLName+\n " );
541544 debug (trace) scope (success) printf( " parseLName-\n " );
542545
546+ static if (__traits(hasMember, Hooks, " parseLName" ))
547+ if (size_t num = hooks.parseLName(this ))
548+ return num;
549+
543550 if ( front == ' Q' )
544551 {
545552 // back reference to LName
@@ -797,6 +804,10 @@ pure:
797804 " dchar" , // w
798805 ];
799806
807+ static if (__traits(hasMember, Hooks, " parseType" ))
808+ if (auto n = hooks.parseType(this , name))
809+ return n;
810+
800811 debug (trace) printf( " parseType+\n " );
801812 debug (trace) scope (success) printf( " parseType-\n " );
802813 auto beg = len;
@@ -1988,7 +1999,7 @@ pure:
19881999char [] demangle ( const (char )[] buf, char [] dst = null )
19892000{
19902001 // return Demangle(buf, dst)();
1991- auto d = Demangle(buf, dst);
2002+ auto d = Demangle! () (buf, dst);
19922003 return d.demangleName();
19932004}
19942005
@@ -2006,10 +2017,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
20062017*/
20072018char [] demangleType ( const (char )[] buf, char [] dst = null )
20082019{
2009- auto d = Demangle(buf, dst);
2020+ auto d = Demangle! () (buf, dst);
20102021 return d.demangleType();
20112022}
20122023
2024+ /**
2025+ * reencode a mangled symbol name that might include duplicate occurrences
2026+ * of the same identifier by replacing all but the first occurence with
2027+ * a back reference.
2028+ *
2029+ * Params:
2030+ * mangled = The mangled string representing the type
2031+ *
2032+ * Returns:
2033+ * The mangled name with deduplicated identifiers
2034+ */
2035+ char [] reencodeMangled (const (char )[] mangled) nothrow pure @safe
2036+ {
2037+ static struct PrependHooks
2038+ {
2039+ size_t lastpos;
2040+ char [] result;
2041+ size_t [const (char )[]] idpos; // identifier positions
2042+
2043+ static struct Replacement
2044+ {
2045+ size_t pos; // postion in original mangled string
2046+ size_t respos; // postion in result string
2047+ }
2048+ Replacement [] replacements;
2049+
2050+ pure :
2051+ size_t positionInResult (size_t pos)
2052+ {
2053+ foreach_reverse (r; replacements)
2054+ if (pos >= r.pos)
2055+ return r.respos + pos - r.pos;
2056+ return pos;
2057+ }
2058+
2059+ alias Remangle = Demangle! (PrependHooks);
2060+
2061+ size_t parseLName (ref Remangle d)
2062+ {
2063+ if (lastpos < d.pos)
2064+ result ~= d.buf[lastpos .. d.pos];
2065+ else if (lastpos > d.pos)
2066+ {
2067+ // todo: roll back to earlier position
2068+ }
2069+
2070+ auto reslen = result.length;
2071+ auto refpos = d.pos;
2072+ if (d.front == ' Q' )
2073+ {
2074+ size_t npos;
2075+ {
2076+ scope (exit) result.length = reslen; // remove all intermediate additions
2077+ // only support identifier back references
2078+ d.popFront();
2079+ size_t n = d.decodeNumber! ' A' ();
2080+ if (! n || n > refpos)
2081+ d.error(" invalid back reference" );
2082+
2083+ auto savepos = d.pos;
2084+ scope (exit) d.pos = savepos;
2085+ size_t srcpos = refpos - n;
2086+
2087+ auto idlen = d.decodeNumber();
2088+ if (d.pos + idlen > d.buf.length)
2089+ d.error(" invalid back reference" );
2090+ auto id = d.buf[d.pos .. d.pos + idlen];
2091+ auto pid = id in idpos;
2092+ if (! pid)
2093+ d.error(" invalid back reference" );
2094+ npos = positionInResult(* pid);
2095+ }
2096+ encodeBackref(reslen - npos, ' A' );
2097+ replacements ~= Replacement(d.pos, result.length);
2098+ }
2099+ else
2100+ {
2101+ auto n = d.decodeNumber();
2102+ if (! n || n > d.buf.length || n > d.buf.length - d.pos)
2103+ d.error(" LName too shot or too long" );
2104+ auto id = d.buf[d.pos .. d.pos + n];
2105+ d.pos += n;
2106+ if (auto pid = id in idpos)
2107+ {
2108+ size_t npos = positionInResult(* pid);
2109+ result.length = reslen;
2110+ encodeBackref(reslen - npos, ' A' );
2111+ replacements ~= Replacement(d.pos, result.length);
2112+ }
2113+ else
2114+ {
2115+ idpos[id] = refpos;
2116+ result ~= d.buf[refpos .. d.pos];
2117+ }
2118+ }
2119+ lastpos = d.pos;
2120+ return 1 ;
2121+ }
2122+
2123+ char [] parseType ( ref Remangle d, char [] name = null )
2124+ {
2125+ if (d.front != ' Q' )
2126+ return null ;
2127+
2128+ if (lastpos < d.pos)
2129+ result ~= d.buf[lastpos .. d.pos];
2130+ else if (lastpos > d.pos)
2131+ {
2132+ // todo: roll back to earlier position
2133+ }
2134+
2135+ auto refPos = d.pos;
2136+ d.popFront();
2137+ auto n = d.decodeNumber! ' a' ();
2138+ if (n == 0 || n > refPos)
2139+ d.error(" invalid back reference" );
2140+
2141+ size_t npos = positionInResult(refPos - n);
2142+ size_t reslen = result.length;
2143+ encodeBackref(reslen - npos, ' a' );
2144+
2145+ lastpos = d.pos;
2146+ return result[reslen .. $]; // anything but null
2147+ }
2148+
2149+ void encodeBackref (size_t relpos, char lastDigitBase)
2150+ {
2151+ result ~= ' Q' ;
2152+ size_t div = 1 ;
2153+ while (relpos >= div * 10 )
2154+ div *= 10 ;
2155+ while (div >= 10 )
2156+ {
2157+ auto dig = (relpos / div);
2158+ result ~= cast (char )(' 0' + dig);
2159+ relpos -= dig * div;
2160+ div /= 10 ;
2161+ }
2162+ result ~= cast (char )(lastDigitBase + relpos);
2163+ }
2164+ }
2165+
2166+ auto d = Demangle! (PrependHooks)(mangled, null );
2167+ d.hooks = PrependHooks();
2168+ d.mute = true ; // no demangled output
2169+ try
2170+ {
2171+ () @trusted { d.parseMangledName(); }();
2172+ if (d.hooks.lastpos < d.pos)
2173+ d.hooks.result ~= d.buf[d.hooks.lastpos .. d.pos];
2174+ return d.hooks.result;
2175+ }
2176+ catch (Exception )
2177+ {
2178+ // overflow exception cannot occur
2179+ return mangled.dup ;
2180+ }
2181+ }
20132182
20142183/**
20152184 * Mangles a D symbol.
@@ -2071,7 +2240,11 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
20712240 }
20722241 dst[i .. i + T.mangleof.length] = T.mangleof[];
20732242 i += T.mangleof.length;
2074- return dst[0 .. i];
2243+
2244+ static if (hasTypeBackRef)
2245+ return reencodeMangled (dst[0 .. i]);
2246+ else
2247+ return dst[0 .. i];
20752248}
20762249
20772250
@@ -2131,12 +2304,15 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
21312304 }
21322305}
21332306
2307+ private enum hasTypeBackRef = (int function (void ** ,void ** )).mangleof[$- 4 .. $] == " QdZi" ;
21342308
21352309// /
21362310unittest
21372311{
21382312 assert (mangleFunc! (int function (int ))(" a.b" ) == " _D1a1bFiZi" );
2139- assert (mangleFunc! (int function (Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFC6ObjectZi" );
2313+ assert (mangleFunc! (int function (Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFCQ1IZi" );
2314+ version (hasTypeBackRef)
2315+ assert (mangleFunc! (int function (Object , Object ))(" object.Object.opEquals" ) == " _D6object6Object8opEqualsFCQ1IQeZi" );
21402316}
21412317
21422318unittest
@@ -2376,7 +2552,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
23762552 break ;
23772553 s ~= s[$ - zpos .. $ - zpos + zlen];
23782554 }
2379- else if ( Demangle.isAlpha(cast (char )ch) || Demangle.isDigit(cast (char )ch) || ch == ' _' )
2555+ else if ( Demangle! () .isAlpha(cast (char )ch) || Demangle! () .isDigit(cast (char )ch) || ch == ' _' )
23802556 s ~= cast (char ) ch;
23812557 else
23822558 {
0 commit comments