| |
|
cy
| I know macros are an unpopular subject in D, but I think there's a way to get mostly equivalent capabilities to macros, without changing the language at all, simply by standardizing access to the compiler's own D language parser.
There are already 10 separate parsers for D here:
http://wiki.dlang.org/Lexers_Parsers
All these parsers are pretty much written from scratch (one even forked from dmd itself) and they all do pretty much the same thing: take a string of code, and turn it into an AST. Turning that AST back into valid D code is itself a rather difficult and error prone process, but if you could, then you could simply do something like:
import some.parser;
string foo(string bar) = unparse(IfDeclaration(parse(bar),parse(q{writeln("yay")}),parse(q{writeln("boo")}));
void main() {
mixin foo!"true";
mixin foo!"false";
}
D isn't a particularly hard to parse language, so it's not too hard to implement these parsers, but they're definitely reinventing the wheel, and there's no assurance that future language features won't break them. But within each D compiler (I'm pretty sure?) there is already a parser, that produces (and manipulates) an AST. For DMD, the parser is written in D itself! Using it would (in theory) be as simple as copying all the ddmd modules into your source directory and importing ddmd.parse. Eliminating the need to maintain all those third party parsers is as simple as having the compiler itself provide the parser as a module.
There is additionally a huge advantage to code being able to use the compiler's D parser, that third party parsers cannot match. The D compiler actually uses the AST generated by its parser. With the other parsers, you have to somehow figure out how to "unparse" their AST into an opaque string of D code, before you can supply that new code as a mixin, but if you used the compiler's own parser, it could accept an AST as a mixin omitting the "parse" step it normally does on mixins.
So the above would end up more like:
import std.parser;
AST foo(string bar) = IfDeclaration(parse(bar), parse(q{writeln("yay")}), parse(q{writeln("boo")}));
void main() {
mixin foo!"true";
mixin foo!"false";
}
omitting the complicated and error prone "unparse()" step entirely, not to mention removing the degradation in compilation speed if you have to unparse, and then re-parse an AST.
I'm not sure if it would be possible to have the parser available at runtime, but it seems like you could compile it into the program just like any other module.
|