简体   繁体   English

如何创建一个生成一个在Haxe中按名称动态知道的构造函数数组的宏?

[英]How to create a macro that generates an array of constructors known dynamically by name in Haxe?

I'm targeting javascript . 我的目标是javascript

I have a macro that runs on Context.onGenerate() that saves a subset of fully qualified type names to a file. 我有一个在Context.onGenerate()上运行的宏,它将完全限定类型名称的子集保存到文件中。 Then, another build macro (which would run on the next buid) reads the list of type names from the file in order to create add a static field to a class which is supposed to hold those types (constructors) in the array. 然后,另一个构建宏(将在下一个buid上运行)从文件中读取类型名称列表,以便创建向一个类添加静态字段,该类应该在数组中保存这些类型(构造函数)。

The field which I want to generate from the second macro would be something like this: 我想从第二个宏生成的字段将是这样的:

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

Which would generate the following javascript 哪个会生成以下javascript

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

Now I've tried writing the field manually to make sure everything generates properly--it does. 现在我尝试手动编写字段以确保一切正常生成 - 确实如此。 However I can't figure out the right way to write the macro, I get stuck on adding a identifier constant as the value of the array expression, which always ends up in a "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" } ]}
              )
});

Is what I'm trying to accomplish possible with macros? 我正在尝试用宏来完成什么? If so could direct me in the steps to accomplish this? 如果是这样可以指导我完成这个步骤?

Thank you. 谢谢。

The problem is that you're trying to output it as a single identifier while it's in fact a dot-path, which should be represented as a chain of EField s to a first EIdent . 问题是,你想输出它作为一个标识符,而它实际上是一个点的路径,这应该被表示为链EField s到第一EIdent Luckily, Haxe has a handy "path" reification right for that: try $p{path.split(".")} (where path is your "entities.Foo" string). 幸运的是,Haxe有一个方便的“路径” 具体权利:尝试$p{path.split(".")} (其中path是你的"entities.Foo"字符串)。

After a bit more digging on the API reference I figured out how to do it. 在对API参考进行了一些挖掘后,我想出了如何做到这一点。 It turns out I needed TypedExpr instead of just an identifier constant. 事实证明我需要TypedExpr而不仅仅是标识符常量。

A TTypeExpr with a ModuleType of TClassDecl would yield the correct result. 模块类型TClassDeclTTypeExpr将产生正确的结果。 So my example code above becomes: 所以上面的示例代码变成:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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