You can start with this
var someFunc = Macro.transform( (s: String) -> if ( a > b ) Math.random() else 2 );
Where the transform
function is a public static macro function
inside a Macro
.hx class
public static macro function transform(expr:haxe.macro.Expr) {
trace(expr);
return macro $expr;
}
This macro logs the expression that comes in, and just returns the expression too.
At this point its a matter of extracting the variable. This can be done with pattern matching.
Lets start the pattern matching with an easier example:
var someFunc = Macro.transform( () -> { trace(1); } );
Then we can use this to match
class Macro {
public static macro function transform(expr:haxe.macro.Expr) {
switch (expr) {
case macro () -> $b{functionBody}:
trace("it matches:", functionBody);
case _:
trace("it doesn't match");
}
return macro $expr;
}
}
Notice that $b { }
is used to match a block expression (see Expression Reification in manual).
Now, that already seems to match
Let’s take it bit more forward:
var a = 3;
var b = 5;
var someFunc = Macro.transform( () -> { if (a>b) 5 else 3; } );
Then add a switch on the functionBody
class Macro {
public static macro function transform(expr:haxe.macro.Expr) {
switch (expr) {
case macro () -> $b{ functionBody}:
trace("it matches:", functionBody);
switch (functionBody[0]) {
case macro if ($e{cond}) $e{first} else $e{second}:
trace("condition:", cond);
trace("if:", first );
trace("else:", second );
case _:
trace("it doens't match here too");
}
case _:
trace("it doesn't match");
}
return macro $expr;
}
}
Some interesting notes:
$b{exprs}
is EBlock(exprs)
, so for convenience I just use functionBody[0]
.
$e { }
is used to match a expression (see Expression Reification in manual)
Now I hope this should give you enough to keep going Enjoy!
Bonus level: Instead of a static function, you could use meta data and use build macro to detect that (or you could make a build macro that tests on all expressions but that can be quite heavy.)
var someFunc = @:magicalTransform () -> { if (a>b) 5 else 3; };