简体   繁体   中英

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.

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]);

.distinct() is only available when you have using thx.Arrays in the module calling the function. When you generate the expression with macro, you cannot guarantee the callsite has the using in place. So you should use the static call instead:

This should work for your code:

public static macro function allOf(indexClasses:Array<ExprOf<Class<Component>>>) {
    var indices = macro Matcher.classesToIndices($a{indexClasses});
    var e = macro $a{indices}; // putting $a{} directly in function call will be reified as argument list, so we store the expression first
    return macro thx.Arrays.distinct($e);
}

Also see this working example on try haxe: http://try-haxe.mrcdk.com/#9B5d6

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM