@@ -24,7 +24,9 @@ else version (WatchOS)
24
24
debug (trace) import core.stdc.stdio : printf;
25
25
debug (info) import core.stdc.stdio : printf;
26
26
27
- private struct Demangle
27
+ private struct NoHooks {}
28
+
29
+ private struct Demangle (Hooks = NoHooks)
28
30
{
29
31
// NOTE: This implementation currently only works with mangled function
30
32
// names as they exist in an object file. Type names mangled via
71
73
size_t brp = 0 ; // current back reference pos
72
74
AddType addType = AddType.yes;
73
75
bool mute = false ;
76
+ Hooks hooks;
74
77
75
78
static class ParseException : Exception
76
79
{
@@ -540,6 +543,10 @@ pure:
540
543
debug (trace) printf( " parseLName+\n " );
541
544
debug (trace) scope (success) printf( " parseLName-\n " );
542
545
546
+ static if (__traits(hasMember, Hooks, " parseLName" ))
547
+ if (size_t num = hooks.parseLName(this ))
548
+ return num;
549
+
543
550
if ( front == ' Q' )
544
551
{
545
552
// back reference to LName
@@ -797,6 +804,10 @@ pure:
797
804
" dchar" , // w
798
805
];
799
806
807
+ static if (__traits(hasMember, Hooks, " parseType" ))
808
+ if (auto n = hooks.parseType(this , name))
809
+ return n;
810
+
800
811
debug (trace) printf( " parseType+\n " );
801
812
debug (trace) scope (success) printf( " parseType-\n " );
802
813
auto beg = len;
@@ -1988,7 +1999,7 @@ pure:
1988
1999
char [] demangle ( const (char )[] buf, char [] dst = null )
1989
2000
{
1990
2001
// return Demangle(buf, dst)();
1991
- auto d = Demangle(buf, dst);
2002
+ auto d = Demangle! () (buf, dst);
1992
2003
return d.demangleName();
1993
2004
}
1994
2005
@@ -2006,10 +2017,168 @@ char[] demangle( const(char)[] buf, char[] dst = null )
2006
2017
*/
2007
2018
char [] demangleType ( const (char )[] buf, char [] dst = null )
2008
2019
{
2009
- auto d = Demangle(buf, dst);
2020
+ auto d = Demangle! () (buf, dst);
2010
2021
return d.demangleType();
2011
2022
}
2012
2023
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
+ }
2013
2182
2014
2183
/**
2015
2184
* Mangles a D symbol.
@@ -2071,7 +2240,11 @@ char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
2071
2240
}
2072
2241
dst[i .. i + T.mangleof.length] = T.mangleof[];
2073
2242
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];
2075
2248
}
2076
2249
2077
2250
@@ -2131,12 +2304,15 @@ char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure no
2131
2304
}
2132
2305
}
2133
2306
2307
+ private enum hasTypeBackRef = (int function (void ** ,void ** )).mangleof[$- 4 .. $] == " QdZi" ;
2134
2308
2135
2309
// /
2136
2310
unittest
2137
2311
{
2138
2312
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" );
2140
2316
}
2141
2317
2142
2318
unittest
@@ -2376,7 +2552,7 @@ string decodeDmdString( const(char)[] ln, ref size_t p )
2376
2552
break ;
2377
2553
s ~= s[$ - zpos .. $ - zpos + zlen];
2378
2554
}
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 == ' _' )
2380
2556
s ~= cast (char ) ch;
2381
2557
else
2382
2558
{
0 commit comments