COMMUNITY

Passing Functions to a Build Macro?

Short: I load json data with a macro and make it the fields of a Class. I also can override these values at runtime by loading a json file. In the macro I transform some of the values, and I do the same at runtime. I want to unify this so the Macro and the Class use the same transformation function.

I want to have some styling settings stored in a json file that can be edited and loaded into the code on build (so i can use autocomplete) and at runtime (so i / user can change the values later).

Currently there are 2 different set of functions that do the same thing. Some functions are with the build macro (transforming the values if required), and some functions with the Class (doing the same transformation). Is there a way to have the Macro use the function in the class? I looked in the Array in the macro and found the FFunc but I don’t know how to call it or execute it.

for example (not real code):

{
    "color" : [255, 255, 255, 255]
}

to

@:build(myfunc())
class Configuration {
    
    // generated by macro
    public var color : Int = 0xFFFFFF;
    
    // generated by macro
    public var alpha : Float = 1.0;

    public function new() { /* .... */ }

    public function load(file : String) {
            // loads the file
    }

    private function transform(k : Key, v : Dynamic) {
        // modifies the loaded json data.
    }
    //

So I’d like to access the transform function in the macro when loading the json and apply it to all the keys in this case.

As a rule, this is not possible, because the code in transform could rely on JS-specific code that can’t run on the macro interpreter.

Given a narrow set of constraints, it might be possible though. You could, for example:

  • grab the haxe.macro.Function corresponding to transform
  • grab its body, and haxe.macro.ExprTools.map it to replace all occurrences of k and v
  • use getValue to get the value … note that this is highly limited