gmqcc
gmqcc copied to clipboard
AST Macros
They should work as functions, being inlined at compile time, with each argument simply being an ast itself. Is what I gather of implementing this cleanly. I like Perls quasi keyword, but I don't like how it attempts to do it. Let me suggest an example of how this could work.
macro loop (n) // note no actual "type" on arguments
{
/// {{{ ... }}} like perl
for (float i = 0; i < {{{n}}}; i++) {
{{{body}}}
}
}
void foo() {
loop(100) {
// do stuff
}
}
the {{{}}} are just expansions (via copy) from the AST's end. There are some implicit ones we can generate from them, like {{{body}}}, which would be the body added around the invocation of loop itself (so that the loop gets the body). The reason we need these sorts of predefined ASTs is because making loop work with the body as an argument, i.e:
macro loop(n,b) { for(float i = 0; i < {{{n}}}; i++) {{{b}}} }
would require loop to be used as:
loop(100, {/* code */})
Which looks very terrible.
Might be good do note that when they are AST macros and you don't actually use a {{{body}}}
in there, then the following will NOT work:
macro for_stuff(n) { for (float i = 0; i < n; ++i) }
// used as
for_stuff(5) {
print("Foo\n");
}
because parsing the macro definition itself will give you a parse error about a missing body for the for
loop in it.
The nice part about ast macros is that a lot of checking (specifically syntax within the macro definition) will happen while parsing the macro definition, so if there's a syntax error it'll be shown in there. While with the preprocessor macros you'll end up getting an error at each use of the macro, and with huge macros it's hard to find the actual point of failure. Plus, there'll be syntax checking at the macro's use for the actual parameters directly.
It may be good to have the possibility to request a specific type in a macro parameter though. So that for instance the macro can create a counter variable accessible in the body by taking a variable-name as parameter. Note that in the above macro, the i
will not be accessible if we have hygienic macros!
Implementation wise we'd need to add copy-ctors to ast nodes. Which are also required for inlining. So I'm referencing #35 here.
I would also like AST macros to return values (e.g. by also adding a syntax like gcc's ({ ... }) construct.
Furthermore, I would really also like a replacement for #ifdef
Will this work? If yes, why is x in the right scope? If no, why not?
macro do { {{{body}}} }
do { float x; }
do { float foo() { return x; } }
Or would it be better to have a second simple CPP mode that only supports argumentless #define/#undef and #ifdef/#else/#endif?