Search code examples
macroshaxe

Apply a function on array of values inside Haxe macro


I generate an array of Int inside Haxe macro and would like to apply a function on it like this:

typedef ComponentIdArray = Array<Int>;

class MyMacros {
    // Each descendant of 'Component' has static member 'id_'
    // Convert array of classes to corresponding indices
    public static macro function classesToIndices(indexClasses:Array<ExprOf<Class<Component>>>) {
        var ixs = [for (indexClass in indexClasses) {macro $indexClass.id_ ;}];
        return macro $a{ixs};
    }

    public static macro function allOf(indexClasses:Array<ExprOf<Class<Component>>>) {
        var indices = macro Matcher.classesToIndices($a{indexClasses});
        // FIXME
        // FIXME 'distinct' is a function from thx.core -- DOES NOT WORK
        //var indices2 = macro ($a{indices}.distinct());
        return macro MyMacros.allOfIndices($indices);
    }


    public static function allOfIndices(indices:ComponentIdArray) {
        trace(indices);
        //... normal function
        // currently I call indices.distinct() here
        return indices.distinct();
    }
}

Usage:

class C1 extends Component {} // C1.id_ will be set to 1
class C2 extends Component {} // C2.id_ will be set to 2
var r = MyMacros.allOf(C1, C2, C1); // should return [1,2]

Since everything is known compile-time I would like to do this in macro.


Solution

  • KevinResoL's answer is basically correct, except it seems you want distinct() to be executed at compile-time (as you can see in try.haxe's output tab, the generated JS code contains the thx.Arrays.distinct() call).

    The easiest solution is probably to call distinct() right away in allOf():

    using haxe.macro.ExprTools;
    
    public static macro function allOf(indexClasses:Array<ExprOf<Class<Component>>>) {
        indexClasses = indexClasses.distinct(function(e1, e2) {
            return e1.toString() == e2.toString();
        });
        var indices = macro Matcher.classesToIndices($a{indexClasses});
        return macro MyMacros.allOfIndices($indices);
    }
    

    As you can see, you also need to define a custom predicate for distinct(), since you're comparing expressions - by default it uses a simple equality check (==), which isn't good enough.

    The generated code looks like this (if the id_ variables are declared inline):

    var r = MyMacros.allOfIndices([1, 2]);