Search code examples
macroshaxe

Generate constructor call with build macro


How can I generate a main() (access) method for a Haxe class with a constructor call?

For example

static function main() new App()

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

and I want to create this with macro, like this:

import haxe.macro.Context;
import haxe.macro.Expr;

class Build {
    macro public static function buildFields():Array<Field> {
        var fields:Array<Field> = Context.getBuildFields();
        var cls = Context.getLocalClass().get();
        var pack = cls.pack.concat([cls.name]);
        var name = pack.join(".");

        fields.push({
            name: "main",
            access: [Access.APublic, Access.AStatic],
            kind: FieldType.FFun({
                expr: macro {
                    Type.createInstance(Type.resolveClass($v{name}), []);
                },
                args: [],
                ret: null
            }),
            pos: Context.currentPos()
        });

        return fields;
    }
}
@:build(Build.buildFields())
class App {
    function new() {
        //....
    }
}

This generates the main() method fine, but I'm not sure how to generate new App() instead of resorting to Type.createInstance().


Solution

  • To generate a constructor call like new App(), you can reify a haxe.macro.TypePath as documented here.

    var typePath:haxe.macro.TypePath = {
        pack: cls.pack,
        name: cls.name
    }
    
    expr: macro new $typePath(),
    

    Btw, instead of manually constructing fields like that, I would suggest using class reification, which lets you use regular Haxe syntax for declaring fields:

    fields = fields.concat((macro class {
        public static function main() {
            new $typePath();
        }
    }).fields);