Create a gist now

Instantly share code, notes, and snippets.

@YellowAfterlife /FTW.hx forked from dpeek/FTW.hx
Last active Dec 28, 2015

import haxe.macro.Expr;
import haxe.macro.Context;
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);
return field;
static function transformExpr(expr:Expr) switch (expr) {
case macro @for($init, $cond, $incr) $block:
expr.expr = makeLoop(init, cond, incr, block).expr;
haxe.macro.ExprTools.iter(expr, transformExpr);
static function makeLoop(init:Expr, cond:Expr, incr:Expr, block:Expr) {
var outer:Array<Expr> = [], inner:Array<Expr> = [];
// adds expression(s) into given list (block):
function unroll(o:Expr, to:Array<Expr>) {
switch (o.expr) {
case EBlock(m): for (v in m) to.push(v);
default: to.push(o);
// inner (inside the for-loop) block:
inner.push(macro var _ = true);
expr: ExprDef.EWhile(macro _ = false, block, false),
pos: block.pos
inner.push(macro if (_) break);
unroll(incr, inner);
// outer (outside the for-loop) block:
unroll(init, outer);
expr: ExprDef.EWhile(cond, {
expr: ExprDef.EBlock(inner),
pos: block.pos
}, true),
pos: block.pos
return {
expr: ExprDef.EBlock(outer),
pos: init.pos
class Main {
static function main() {
@for( { var i = 0, j = -5; } , i < 5 && j < 0, { i++; j++; } ) {
trace('Step $i, $j');
lpetre commented Nov 20, 2013

This is great (I got here from the parent gist). I wonder how compiler optimizations will handle the result, vs haxe just supporting a c-style for loop.


Is there actually a compelling argument/discussion around the lack of c-style for loops in Haxe?


None really, its just Nicolas don't liking C-fors ( there is support for while but not for ) which is a shame because Haxe borrows a lot of AS3 syntax except one of the most used AS3 idiom constructs making porting AS3 games more of a hassle that it could be.

One question in the line: macro @for($init , $cond , $incr) $block:
is there some way to tell Haxe to accept: @for($init EConst(';') $cond EConst(';') $incr) $block:


The best you can do to approach the semicolons is around

@for({ var i = 0; i < 5; i++; }) trace(i);

... which is still pretty strange.

The general conclusion here is, that whatever you do about for-loops, they will never feel right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment