How do I create a macro that generates an array of constructors dynamically known by name in Haxe?

I am targeting javascript .

I have a macro that runs on Context.onGenerate () that saves a subset of the fully qualified type names to a file. Then another build macro (which will run on the next buid) reads the list of type names from the file to create a static field addition to the class that should contain those types (constructors) in an array.

The field I want to create from the second macro would be something like this:

public static _entities:Array<Class<entities.Entity>> = [
    entities.Foo,
    entities.Bar,
    ...
];

      

To create the following javascript

MyClass._entities = [ entities_Foo, entities_Bar, ... ];

      

Now I tried to write the field by hand to make sure everything is generated correctly - it does. However, I cannot figure out how to write the macro correctly, I am stuck with adding an identifier constant as the value of an array expression, which always ends up with an "Unknown identifier" error :

var id = { expr: EConst( CIdent( "entities.Foo" ) ), 
           pos: Context.currentPos() };

var ex  = EArrayDecl([ id ]);

fields.push( {
    name    : "_entities",
    access  : [Access.APublic, Access.AStatic ],
    pos     : Context.currentPos(),
    kind    : FVar( 
                macro:Array<Class<entities.Entity>>,

                // I've tried writing it without reification: (see above vars)
                { expr: ex, pos:Context.currentPos() }

                // Or w/ reification:
                macro $a{[ $i{ "entities.Foo" } ]}
              )
});

      

Am I trying to do this using macros? If this could guide me in steps to accomplish this?

Thank.

+3


source to share


2 answers


The problem is that you are trying to output it as a single identifier, and in fact it is a dotted path that should be presented as a string EField

for the first one EIdent

. Fortunately, Haxe has a convenient reification "way" for this: try $p{path.split(".")}

(where path

is your "entities.Foo"

string).



+4


source


After a bit more in-depth searching for API references, I figured out how to do this. It turns out I need TypedExpr instead of an id constant.

A TTypeExpr with a ModuleType TClassDecl will give the correct result. So my example code above is:



static function getTypeRef( name:String ):Ref<ClassType>
{
    var type = Context.getType( name );

    switch( type )
    {
        default: return Context.error( "Expected a ClassType", Context.currentPos() );
        case TInst( cr, _ ):
            return cr;
    }
}


static function getTypes()
{
    // Obtain ClassType by identifier
    var fooCls = getTypeRef( "entities.Foo" );

    // Get a TypedExpr for the ClassType
    var typedExpr:TypedExpr = {
        expr : TTypeExpr( TClassDecl( fooCls ) ),
        t    : TInst( fooCls, [] ),
        pos  : Context.currentPos()
    };

    // Convert to Expr
    var expr:Expr = Context.getTypedExpr( typedExpr );

    var fields = Context.getBuildFields();

    fields.push( {
        name    : "_entities",
        access  : [Access.APublic, Access.AStatic ],
        pos     : Context.currentPos(),
        kind    : FVar( 
                    macro:Array<Class<entities.Entity>>,
                    macro $a{[ ${expr} ]}   // <- Now it works here
                  )
    });

    return fields;
}

      

+1


source







All Articles