enum AddType { no, yes }
- this( const(char)[] buf_, char[] dst_ = null )
+ this( return const(char)[] buf_, return char[] dst_ = null )
{
this( buf_, AddType.yes, dst_ );
}
- this( const(char)[] buf_, AddType addType_, char[] dst_ = null )
+ this( return const(char)[] buf_, AddType addType_, return char[] dst_ = null )
{
buf = buf_;
addType = addType_;
{
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];
- len -= val.length;
}
}
- char[] append( const(char)[] val )
+ char[] append( const(char)[] val ) return scope
{
pragma(inline, false); // tame dmd inliner
assert( !contains( dst[0 .. len], val ) );
debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
- if ( &dst[len] == &val[0] &&
- dst.length - len >= val.length )
+ if ( dst.length - len >= val.length && &dst[len] == &val[0] )
{
// data is already in place
auto t = dst[len .. len + val.length];
put(", ");
}
- char[] put(char c)
+ char[] put(char c) return scope
{
char[1] val = c;
return put(val[]);
}
- char[] put( const(char)[] val )
+ char[] put( scope const(char)[] val ) return scope
{
pragma(inline, false); // tame dmd inliner
{
import core.internal.string;
- UnsignedStringBuf buf;
+ UnsignedStringBuf buf = void;
- auto s = unsignedToTempString(val, buf, 16);
+ auto s = unsignedToTempString!16(val, buf);
int slen = cast(int)s.length;
if (slen < width)
{
}
- void silent( lazy void dg )
+ void silent( void delegate() pure @safe dg )
{
debug(trace) printf( "silent+\n" );
debug(trace) scope(success) printf( "silent-\n" );
Digit
Digit Number
*/
- const(char)[] sliceNumber()
+ const(char)[] sliceNumber() return scope
{
debug(trace) printf( "sliceNumber+\n" );
debug(trace) scope(success) printf( "sliceNumber-\n" );
}
- size_t decodeNumber()
+ size_t decodeNumber() scope
{
debug(trace) printf( "decodeNumber+\n" );
debug(trace) scope(success) printf( "decodeNumber-\n" );
}
- size_t decodeNumber( const(char)[] num )
+ size_t decodeNumber( scope const(char)[] num ) scope
{
debug(trace) printf( "decodeNumber+\n" );
debug(trace) scope(success) printf( "decodeNumber-\n" );
}
- void parseReal()
+ void parseReal() scope
{
debug(trace) printf( "parseReal+\n" );
debug(trace) scope(success) printf( "parseReal-\n" );
Namechar
Namechar Namechars
*/
- void parseLName()
+ void parseLName() scope
{
debug(trace) printf( "parseLName+\n" );
debug(trace) scope(success) printf( "parseLName-\n" );
TypeTuple:
B Number Arguments
*/
- char[] parseType( char[] name = null )
+ char[] parseType( char[] name = null ) return scope
{
static immutable string[23] primitives = [
"char", // a
return dst[beg .. len];
case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
return parseTypeFunction( name );
- case 'I': // TypeIdent (I LName)
case 'C': // TypeClass (C LName)
case 'S': // TypeStruct (S LName)
case 'E': // TypeEnum (E LName)
popFront();
put( "scope " );
continue;
+ case 'm': // FuncAttrLive
+ popFront();
+ put( "@live " );
+ continue;
default:
error();
}
}
}
- void parseFuncArguments()
+ void parseFuncArguments() scope
{
// Arguments
for ( size_t n = 0; true; n++ )
}
switch ( front )
{
- case 'J': // out (J Type)
+ case 'I': // in (I Type)
popFront();
- put( "out " );
+ put("in ");
+ if (front == 'K')
+ goto case;
parseType();
continue;
case 'K': // ref (K Type)
put( "ref " );
parseType();
continue;
+ case 'J': // out (J Type)
+ popFront();
+ put( "out " );
+ parseType();
+ continue;
case 'L': // lazy (L Type)
popFront();
put( "lazy " );
TypeFunction:
CallConvention FuncAttrs Arguments ArgClose Type
*/
- char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no )
+ char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return
{
debug(trace) printf( "parseTypeFunction+\n" );
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
E
F
*/
- void parseValue( char[] name = null, char type = '\0' )
+ void parseValue(scope char[] name = null, char type = '\0' ) scope
{
debug(trace) printf( "parseValue+\n" );
debug(trace) scope(success) printf( "parseValue-\n" );
}
put( ')' );
return;
+ case 'f':
+ // f MangledName
+ // A function literal symbol
+ popFront();
+ parseMangledName(false, 1);
+ return;
default:
error();
}
}
- void parseIntegerValue( char[] name = null, char type = '\0' )
+ void parseIntegerValue( scope char[] name = null, char type = '\0' ) scope
{
debug(trace) printf( "parseIntegerValue+\n" );
debug(trace) scope(success) printf( "parseIntegerValue-\n" );
S Number_opt QualifiedName
X ExternallyMangledName
*/
- void parseTemplateArgs()
+ void parseTemplateArgs() scope
{
debug(trace) printf( "parseTemplateArgs+\n" );
debug(trace) scope(success) printf( "parseTemplateArgs-\n" );
char t = front; // peek at type for parseValue
if ( t == 'Q' )
t = peekBackref();
- char[] name; silent( name = parseType() );
+ char[] name; silent( delegate void() { name = parseType(); } );
parseValue( name, t );
continue;
case 'S':
TemplateInstanceName:
Number __T LName TemplateArgs Z
*/
- void parseTemplateInstanceName(bool hasNumber)
+ void parseTemplateInstanceName(bool hasNumber) scope
{
debug(trace) printf( "parseTemplateInstanceName+\n" );
debug(trace) scope(success) printf( "parseTemplateInstanceName-\n" );
}
- bool mayBeTemplateInstanceName()
+ bool mayBeTemplateInstanceName() scope
{
debug(trace) printf( "mayBeTemplateInstanceName+\n" );
debug(trace) scope(success) printf( "mayBeTemplateInstanceName-\n" );
LName
TemplateInstanceName
*/
- void parseSymbolName()
+ void parseSymbolName() scope
{
debug(trace) printf( "parseSymbolName+\n" );
debug(trace) scope(success) printf( "parseSymbolName-\n" );
// 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 )
+ char[] parseFunctionTypeNoReturn( bool keepAttr = false ) return scope
{
// try to demangle a function, in case we are pointing to some function local
auto prevpos = pos;
SymbolName
SymbolName QualifiedName
*/
- char[] parseQualifiedName()
+ char[] parseQualifiedName() return scope
{
debug(trace) printf( "parseQualifiedName+\n" );
debug(trace) scope(success) printf( "parseQualifiedName-\n" );
_D QualifiedName Type
_D QualifiedName M Type
*/
- void parseMangledName( bool displayType, size_t n = 0 )
+ void parseMangledName( bool displayType, size_t n = 0 ) scope
{
debug(trace) printf( "parseMangledName+\n" );
debug(trace) scope(success) printf( "parseMangledName-\n" );
parseMangledName( AddType.yes == addType );
}
- char[] doDemangle(alias FUNC)()
+ 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 )
{
auto msg = e.toString();
printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
}
- if ( dst.length < buf.length )
- dst.length = buf.length;
- dst[0 .. buf.length] = buf[];
- return dst[0 .. buf.length];
+ return copyInput();
}
catch ( Exception e )
{
* The demangled name or the original string if the name is not a mangled D
* name.
*/
-char[] demangle( const(char)[] buf, char[] dst = null ) nothrow pure @safe
+char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe
{
- //return Demangle(buf, dst)();
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();
}
* Returns:
* The mangled name with deduplicated identifiers
*/
-char[] reencodeMangled(const(char)[] mangled) nothrow pure @safe
+char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
{
static struct PrependHooks
{
Replacement [] replacements;
pure @safe:
- size_t positionInResult(size_t pos)
+ size_t positionInResult(size_t pos) scope
{
foreach_reverse (r; replacements)
if (pos >= r.pos)
alias Remangle = Demangle!(PrependHooks);
- void flushPosition(ref Remangle d)
+ void flushPosition(ref Remangle d) scope
{
if (lastpos < d.pos)
{
}
}
- bool parseLName(ref Remangle d)
+ bool parseLName(scope ref Remangle d) scope
{
flushPosition(d);
npos = positionInResult(*pid);
}
encodeBackref(reslen - npos);
- replacements ~= Replacement(d.pos, result.length);
+ const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
+ replacements ~= Replacement(pos, result.length);
}
else
{
size_t npos = positionInResult(*pid);
result.length = reslen;
encodeBackref(reslen - npos);
- replacements ~= Replacement(d.pos, result.length);
+ const pos = d.pos; // work around issues.dlang.org/show_bug.cgi?id=20675
+ replacements ~= Replacement(pos, result.length);
}
else
{
return true;
}
- char[] parseType( ref Remangle d, char[] name = null )
+ char[] parseType( ref Remangle d, char[] name = null ) return scope
{
if (d.front != 'Q')
return null;
return result[reslen .. $]; // anything but null
}
- void encodeBackref(size_t relpos)
+ void encodeBackref(size_t relpos) scope
{
result ~= 'Q';
enum base = 26;
* The mangled name for a symbols of type T and the given fully
* qualified name.
*/
-char[] mangle(T)(const(char)[] fqn, char[] dst = null) @safe pure nothrow
+char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null) @safe pure nothrow
{
import core.internal.string : numDigits, unsignedToTempString;
@property bool empty() const { return !s.length; }
- @property const(char)[] front() const
+ @property const(char)[] front() const return
{
immutable i = indexOfDot();
return i == -1 ? s[0 .. $] : s[0 .. i];
}
- void popFront()
+ void popFront() scope
{
immutable i = indexOfDot();
s = i == -1 ? s[$ .. $] : s[i+1 .. $];
}
- private ptrdiff_t indexOfDot() const
+ private ptrdiff_t indexOfDot() const scope
{
foreach (i, c; s) if (c == '.') return i;
return -1;
* The mangled name for a function with function pointer type T and
* the given fully qualified name.
*/
-char[] mangleFunc(T:FT*, FT)(const(char)[] fqn, char[] dst = null) @safe pure nothrow if (is(FT == function))
+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)
{
private enum hasTypeBackRef = (int function(void**,void**)).mangleof[$-4 .. $] == "QdZi";
-///
@safe pure nothrow unittest
{
assert(mangleFunc!(int function(int))("a.b") == "_D1a1bFiZi");
else
enum string cPrefix = "";
-version (unittest)
+@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)"],
["_D3foo7__arrayZ", "foo.__array"],
["_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
["_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi", "int link6574.foo!(0).foo()"],
- ["_D4test22__T4funcVAyaa3_610a62Z4funcFNaNbNiNfZAya", `pure nothrow @nogc @safe immutable(char)[] test.func!("a\x0ab").func()`],
+ ["_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()"],
"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, "
else
alias staticIota = Seq!(staticIota!(x - 1), x - 1);
}
-}
-@safe pure nothrow unittest
-{
foreach ( i, name; table )
{
auto r = demangle( name[0] );
assert( r == name[1],
- "demangled \"" ~ name[0] ~ "\" as \"" ~ r ~ "\" but expected \"" ~ 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] ~ "\"");
+ "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);
+}
/*
*