January 28, 2015
https://issues.dlang.org/show_bug.cgi?id=14073

          Issue ID: 14073
           Summary: Allow token strings to use other types of brackets as
                    delimiters
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: DMD
          Assignee: nobody@puremagic.com
          Reporter: monkeyworks12@hotmail.com

Currently, token strings *must* use curly brackets as delimiters. I think it would be a useful enhancement if they were able to use other kinds of brackets for delimiters as well. Ex:

string a1 = q[This is a token string];
string a2 = q(This is also a token string];
string a3 = q<Angle brackets are also valid for token strings>;

This is a very simple change that would aid in the creation of DSLs in D. One real-world example:


template crange(string spec)
{
    static processSpec(string spec)
    {
        import std.algorithm;
        import std.ascii;
        import std.conv;
        import std.functional;
        import std.range;
        import std.string;

        return spec.splitter(',').map!((s)
        {
            s = s.strip!(c => c.isWhite || c == '\'');

            auto start = s.front;
            auto end = s.retro.front;

            return start <= end
                ? iota(start, end + 1)
                    .map!(c => cast(dchar)c).array
                : iota(end, start + 1)
                    .retro
                    .map!(c => cast(dchar)c).array;
        }).join;
    }

    enum crange = processSpec(spec);
}

void main(string[] argv)
{
    import std.stdio;

    auto t1 = crange!q{ 'a'..'z', 'A'..'Z', '0'..'9' };
    writeln(t1);

    auto t2 = crange!q{ '9'..'0', 'Z'..'A', 'z'..'a' };
    writeln(t2);
}


This doesn't look too bad, but it would be nice if square brackets could be used instead to better mimic the Pascal feature, and better communicate to the user that an array will be produced. With this enhancement, the above code would become:

void main(string[] argv)
{
    import std.stdio;

    auto t1 = crange!q['a'..'z', 'A'..'Z', '0'..'9'];
    writeln(t1);

    auto t2 = charRange!q['9'..'0', 'Z'..'A', 'z'..'a'];
    writeln(t2);
}

Which I subjectively believe looks better and is more readable. There is no ambiguity here lexer-wise as far as I know, as the q signifies that either a token string or a delimited string follows. It seems to me this change is as simple as a small change in the parser to accept (), <>, and [] brackets for token strings as well as {} brackets.

--