/home/i/wrk/d/dfilt/dfilt.d

private import std.cstream;
private import std.regexp;
private import std.string;
private import std.ctype;
private import std.conv;

class Demangle {
    this() {
        simpleMangle['v'] = "void";
        simpleMangle['g'] = "byte";
        simpleMangle['h'] = "ubyte";
        simpleMangle['s'] = "short";
        simpleMangle['t'] = "ushort";
        simpleMangle['i'] = "int";
        simpleMangle['k'] = "uint";
        simpleMangle['l'] = "long";
        simpleMangle['m'] = "ulong";
        simpleMangle['f'] = "float";
        simpleMangle['d'] = "double";
        simpleMangle['e'] = "real";

        simpleMangle['o'] = "ifloat";
        simpleMangle['p'] = "idouble";
        simpleMangle['j'] = "ireal";
        simpleMangle['q'] = "cfloat";
        simpleMangle['r'] = "cdouble";
        simpleMangle['c'] = "creal";

        simpleMangle['b'] = "bit";
        simpleMangle['a'] = "char";
        simpleMangle['u'] = "wchar";
        simpleMangle['w'] = "dchar";

        simpleMangle['@'] = "???ERROR???";
    }

    void run(Stream ins, Stream outs) {
//        char[] all = ins.toString();
        char[] all = "";
        try {
            int c;
            while ((c = ins.getc()) != char.init) {
                all ~= cast(char)c;
            }
        }
        catch (Error e) {}

        char[][] lines = std.string.split(all, "\n");
        foreach (char[] line; lines) {
            for (int i = 0; i < line.length-1; i++) {
                if (line[i..i+2] == `_D` && (i == 0 || !issym(line[i-1]))) {
                    int j;
                    for (j = i+2; j < line.length; j++) {
                        if (!issym(line[j])) break;
                    }
                    int end = 0;
                    char[] d = demangle(line[i+2..j], end);
                    line = line[0..i] ~ d ~ line[j..line.length];
                }
                if (i < line.length - 7 &&
                    line[i..i+7] == `_Class_` &&
                    (i == 0 || !issym(line[i-1])))
                {
                    int j;
                    for (j = i+7; j < line.length; j++) {
                        if (!issym(line[j])) break;
                    }
                    int end = 0;
                    char[] d = demangle(line[i+7..j], end);
                    line = line[0..i] ~ "class " ~ d ~ line[j..line.length];
                }
            }

            outs.writeLine(line);
        }
    }

    char[] demangle(char[] sym, inout int i) {
        if (sym.length > i+2 && sym[i..i+2] == "_D") i += 2;

        char[][] names;
        while (i < sym.length && std.ctype.isdigit(sym[i])) {
            int num = getNum(sym, i);

            char[] now = sym[i..i+num];

            if (now == "__anonymous") {
            }
            else {
                // @@@ is it ok?
                int sep = std.string.rfind(now, "_");
                if (sep > 0) {
                    try {
                        int dummy = 0;
                        char[] type = demangle(now[sep+1..now.length], dummy);
                        now = now[0..sep] ~ "!(" ~ type ~ ")";
                    }
                    catch (Object o) {}
                }

                names ~= now;
            }

            i += num;
        }
        char[] name = join(names, ".");

        if (sym.length == i) return name;

        char[] type;
    TYPE:
        switch (sym[i]) {
        case 'A': { // array
            i++;
            char[] t = demangle(sym, i);
            type = t ~ "[]";
            break TYPE;
        }
        case 'G': { // static array
            i++;
            char[] num = getNumStr(sym, i);
            char[] t = demangle(sym, i);
            type = t ~ "[" ~ num ~ "]";
            break TYPE;
        }
        case 'H': { // assoc array
            i++;
            char[] t1 = demangle(sym, i);
            char[] t2 = demangle(sym, i);
            type = t2 ~ "[" ~ t1 ~ "]";
            break TYPE;
        }
        case 'P': { // pointer
            i++;
            char[] t = demangle(sym, i);
            type = t ~ "*";
            break TYPE;
        }
        case 'R': { // reference
            assert(false);
            i++;
            char[] t = demangle(sym, i);
            type = "inout " ~ t;
            break TYPE;
        }
        case 'F':
        case 'U': { // (static) function
            bool isStatic = sym[i] == 'U';

            i++;
            char[][] args;
            bool nowRet = false;
            while (1) {
                char[] t = demangle(sym, i);

                if (nowRet) {
                    if (isStatic) t = "static " ~ t;
                    return t ~ " " ~ name ~ "(" ~ join(args, ",") ~ ")";
                }
                if (i == sym.length) {
                    args ~= "...";
                    if (isStatic) t = "static " ~ t;
                    return t ~ " " ~ name ~ "(" ~ join(args, ",") ~ ")";
                }

                args ~= t;

                if (sym[i] == 'Z') {
                    nowRet = true;
                    i++;
                }
                if (sym[i] == 'Y') {
                    i++;
                }
            }
            assert(false);
        }
        case 'I': { // @@@ident?
            assert(false);
        }
        case 'C': { // class
            i++;
            char[] t = demangle(sym, i);
            // @@@
            type = "class " ~ t;
            break TYPE;
        }
        case 'S': { // struct
            i++;
            char[] t = demangle(sym, i);
            // @@@
            type = "struct " ~ t;
            break TYPE;
        }
        case 'E': { // enum
            i++;
            char[] t = demangle(sym, i);
            // @@@
            type = "enum " ~ t;
            break TYPE;
        }
        case 'T': { // typedef
            i++;
            char[] t = demangle(sym, i);
            // @@@
            type = "typedef " ~ t;
            break TYPE;
        }
        case 'D': { // delegate
            // @@@ it should be "int delegate()", not "delegate int ()"
            i++;
            char[] t = demangle(sym, i);
            type = "delegate " ~ t;
            break TYPE;
        }
        case 'K': { // inout
            i++;
            char[] t = demangle(sym, i);
            type = "inout " ~ t;
            break TYPE;
        }
        case 'J': { // out
            i++;
            char[] t = demangle(sym, i);
            type = "out " ~ t;
            break TYPE;
        } 
        case 'Y':
        case 'Z': { // separater
            break TYPE;
        }
        default:
            if (sym[i] in simpleMangle) {
                type = simpleMangle[sym[i]];
                i++;
                break TYPE;
            }

            assert(false);
            break TYPE;
        }

        if (type) {
            if (name && name.length > 0) {
                return type ~ " " ~ name;
            }
            else {
                return type;
            }
        }
        else {
            return name;
        }
    }

private:
    bool issym(char c) {
        return isalnum(c) || c == '_';
    }

    int getNum(char[] str, inout int i) {
        return toInt(getNumStr(str, i));
    }
    char[] getNumStr(char[] str, inout int i) {
        char[] numStr = "";
        while (std.ctype.isdigit(str[i])) {
            numStr ~= str[i];
            i++;
        }
        return numStr;
    }

private:
    char[][char] simpleMangle;

}

version (DFILT_NOMAIN) {
}
else {
    int main(char[][] args) {
        Demangle d = new Demangle();
        d.run(din, dout);

        return 0;
    }
}