-
-
Save dpeek/7476625 to your computer and use it in GitHub Desktop.
-x Main |
import haxe.macro.Expr; | |
class FTW | |
{ | |
public static function build() | |
{ | |
return haxe.macro.Context.getBuildFields().map(transformField); | |
} | |
static function transformField(field:Field) | |
{ | |
switch (field.kind) | |
{ | |
case FFun(f): transformExpr(f.expr); | |
default: | |
} | |
return field; | |
} | |
static function transformExpr(expr:Expr) switch (expr) | |
{ | |
case macro @for($init, $cond, $incr) $block: | |
transformExpr(block); | |
expr.expr = makeLoop(init, cond, incr, block).expr; | |
default: | |
haxe.macro.ExprTools.iter(expr, transformExpr); | |
} | |
static function makeLoop(init:Expr, cond:Expr, incr:Expr, block:Expr) return macro | |
{ | |
$init; | |
while ($cond) | |
{ | |
$block; | |
$incr; | |
} | |
} | |
} |
@:build(FTW.build()) | |
class Main | |
{ | |
static function main() | |
{ | |
@for(var i = 0, i < 10, i++) | |
{ | |
trace('ftw: $i'); | |
} | |
} | |
} |
@nadako thanks for the explanation. Never knew Macro is a meta programming thing.
@YellowAfterlife we could add a helper that allowed you to do: --macro FTW.build('package.name')
Possible workaround allowing both continue and break:
static function makeLoop(init:Expr, cond:Expr, incr:Expr, block:Expr) return macro
{
$init;
if ($cond)
{
do
{
$block;
} while ({ $incr; $cond; });
}
}
(Untested.)
Made a better version:
player-03: Your version combines duplicating code (slightly larger output size) with creating anonymous functions (or even whole classes, if it's C#/Java) on most targets. It's an arguable advancement. Example: http://try.haxe.org/#7F556
A year and a half later, I finally noticed your comment. Sorry for the late response!
Anyway, I figured out that you meant to include a continue
statement in your example, because that's what causes duplicate code. (Or maybe you did include one and try.haxe.org didn't save it. Or maybe Haxe improved over the past 1.5 years, and now it optimizes your example better.)
Whichever it was, I've fixed the issue. My code checks for the existence of continue
and break
statements, and uses the simplest possible loop. Even in the most complicated case, the only code that gets duplicated is "shouldBreak = false
," not any anonymous functions or classes.
While technically pretty cool, current implementation of
makeLoop
breaks the expected behaviour ofcontinue
statement. I've made a fork with that part fixed: https://gist.github.com/YellowAfterlife/7494363One can also workaround with code like
at the price of loosing ability to use
break
statements.But, as said, very interesting. Now I'm starting to get curious whether it's possible to autoinsert @:build into all classes on project level.