Macros 如何在Haxe宏函数中声明实例化

Macros 如何在Haxe宏函数中声明实例化,macros,haxe,Macros,Haxe,我想创建一个宏,为我生成以下代码: if (myEntity.get(Attack) == null) myEntity.add(new Attack()); if (myEntity.get(Confused) == null) myEntity.add(new Confused()); if (myEntity.get(Defend) == null) myEntity.add(new Defend()); if (myEntity.get(Offense) == null) myEntit

我想创建一个宏,为我生成以下代码:

if (myEntity.get(Attack) == null) myEntity.add(new Attack());
if (myEntity.get(Confused) == null) myEntity.add(new Confused());
if (myEntity.get(Defend) == null) myEntity.add(new Defend());
if (myEntity.get(Offense) == null) myEntity.add(new Offense());
在代码中,我想这样声明/使用它:

EntityMacroUtils.addComponents(myEntity, Attack, Confused, Defend, Offense);
macro public static function addComponents(entity:ExprOf<Entity>, components:Array<ExprOf<Class<Component>>>):Expr
{
    var exprs:Array<Expr> = [];
    for (componentClass in components)
    {
        var instance = macro $e { new $componentClass() }; // problem is here
        var expr = macro if ($entity.get($componentClass) == null) $entity.add(instance);
        exprs.push(expr);
    }
    return macro $b{ exprs };
}
import haxe.macro.Expr;
using haxe.macro.Tools;

class Thing {
    public function new(){}
}
class OtherThing {
    public function new(){}
}

class TMacroNew {

    macro static function instances( arr:Array<Expr> ) {

        var news = [for (e in arr) {
            var ct = switch e.expr { case EParenthesis({expr:ECheckType(_,ct)}):ct; case _: throw "nope"; };
            var tp = switch ct { case TPath(tp):tp; case _: throw "nope"; };
            macro new $tp();
        }];
        trace( (macro $b{news}).toString());
        return macro $b{news};
    }


    static function main(){
        instances( (_:Thing), (_:Thing), (_:OtherThing) );
    }
}
当前宏函数如下所示:

EntityMacroUtils.addComponents(myEntity, Attack, Confused, Defend, Offense);
macro public static function addComponents(entity:ExprOf<Entity>, components:Array<ExprOf<Class<Component>>>):Expr
{
    var exprs:Array<Expr> = [];
    for (componentClass in components)
    {
        var instance = macro $e { new $componentClass() }; // problem is here
        var expr = macro if ($entity.get($componentClass) == null) $entity.add(instance);
        exprs.push(expr);
    }
    return macro $b{ exprs };
}
import haxe.macro.Expr;
using haxe.macro.Tools;

class Thing {
    public function new(){}
}
class OtherThing {
    public function new(){}
}

class TMacroNew {

    macro static function instances( arr:Array<Expr> ) {

        var news = [for (e in arr) {
            var ct = switch e.expr { case EParenthesis({expr:ECheckType(_,ct)}):ct; case _: throw "nope"; };
            var tp = switch ct { case TPath(tp):tp; case _: throw "nope"; };
            macro new $tp();
        }];
        trace( (macro $b{news}).toString());
        return macro $b{news};
    }


    static function main(){
        instances( (_:Thing), (_:Thing), (_:OtherThing) );
    }
}
宏公共静态函数addComponents(实体:ExprOf,组件:数组):Expr { 变量表达式:数组=[]; for(组件中的组件类) { var instance=macro$e{new$componentClass()};//这里有问题 var expr=宏if($entity.get($componentClass)==null)$entity.add(实例); expr.push(expr); } 返回宏$b{exprs}; } 此宏函数不正确,我得到错误:

EntityMacroUtils.hx:17:字符22-43:未找到类型:$componentClass

问题是我不知道如何定义
new$componentClass()
。我该如何解决这个问题


我还希望避免在输出代码中使用
Type.createInstance

以编程方式生成实例化代码的一种方法是使用“old school”枚举AST building(兼容的Haxe 3.0.1+):

可以使用物化改进语法:

// new pack.age.TheClass()
var typePath = { name:"TheClass", pack:["pack", "age"], params:[] };
return macro new $typePath();
现在,为了方便地使用“实例化助手”函数语法,我们需要进行一些扭曲,以便从宏函数中接收的表达式中提取类型路径:

// new Foo(), new pack.Bar(), new pack.age.Baz()
instantiate(Foo, pack.Bar, pack.age.Baz);

macro static function instantiate(list:Array<Expr>)
{
    var news = [for (what in list) {
        var tp = makeTypePath(what);
        macro new $tp();
    }];
    return macro $b{news};
}

#if macro
static function makeTypePath(of:Expr, ?path:Array<String>):TypePath 
{
    switch (of.expr)
    {
        case EConst(CIdent(name)):
            if (path != null) {
                path.unshift(name);
                name = path.pop();
            }
            else path = [];
            return { name:name, pack:path, params:[] };

        case EField(e, field):
            if (path == null) path = [field];
            else path.unshift(field);
            return makeTypePath(e, path);

        default:
            throw "nope";
    }
}
#end
//new Foo(),new pack.Bar(),new pack.age.Baz()
实例化(Foo、pack.Bar、pack.age.Baz);
宏静态函数实例化(列表:数组)
{
var news=[用于(列表中的内容){
var tp=makeTypePath(什么);
宏新$tp();
}];
返回宏$b{news};
}
#如果宏
静态函数makeTypePath(of:Expr,?path:Array):TypePath
{
开关(of.expr)
{
案例经济(事件(名称)):
if(路径!=null){
路径.取消移位(名称);
name=path.pop();
}
else路径=[];
返回{name:name,pack:path,params:[]};
案例e字段(e,字段):
如果(path==null)path=[field];
else路径。取消移位(字段);
返回makeTypePath(e,path);
违约:
抛出“不”;
}
}
#结束

如果有人需要答案,我会在Haxe IRC聊天中通过ousado获得这个答案:

如果仅在宏中执行此操作,则可以执行以下操作:

var ct = macro : pack.age.SomeTypename;
var tp = switch ct { case TPath(tp):tp; case _: throw "nope"; }
var expr = macro new $tp();
…或者,如果您显式构造
tp

var tp = {sub:'SomeTypeName',params:[],pack:['pack','age'],name:"SomeModuleName"}
如您所见,这里显式地给出了复杂类型路径

不幸的是,Haxe对于表达式位置的类型并没有一个简洁的语法。您可以传递
(\uux:TypeName)
以提供包含ComplexType的表达式

但如果要将类型作为参数传递,可以这样做:

EntityMacroUtils.addComponents(myEntity, Attack, Confused, Defend, Offense);
macro public static function addComponents(entity:ExprOf<Entity>, components:Array<ExprOf<Class<Component>>>):Expr
{
    var exprs:Array<Expr> = [];
    for (componentClass in components)
    {
        var instance = macro $e { new $componentClass() }; // problem is here
        var expr = macro if ($entity.get($componentClass) == null) $entity.add(instance);
        exprs.push(expr);
    }
    return macro $b{ exprs };
}
import haxe.macro.Expr;
using haxe.macro.Tools;

class Thing {
    public function new(){}
}
class OtherThing {
    public function new(){}
}

class TMacroNew {

    macro static function instances( arr:Array<Expr> ) {

        var news = [for (e in arr) {
            var ct = switch e.expr { case EParenthesis({expr:ECheckType(_,ct)}):ct; case _: throw "nope"; };
            var tp = switch ct { case TPath(tp):tp; case _: throw "nope"; };
            macro new $tp();
        }];
        trace( (macro $b{news}).toString());
        return macro $b{news};
    }


    static function main(){
        instances( (_:Thing), (_:Thing), (_:OtherThing) );
    }
}
导入haxe.macro.Expr;
使用haxe.macro.Tools;
阶级事务{
公共函数new(){}
}
类其他事物{
公共函数new(){}
}
类TMacroNew{
宏静态函数实例(arr:Array){
var新闻=[对于(arr中的e){
var ct=switch e.expr{case-EParenthesis({expr:ECheckType({uu,ct)}):ct;case}:抛出“nope”;};
var-tp=开关ct{case-TPath(tp):tp;case}:抛出“nope”;};
宏新$tp();
}];
trace((宏$b{news}).toString());
返回宏$b{news};
}
静态函数main(){
实例((:事物),(:事物),(:其他事物));
}
}

…如果你想要一个类型列表,你可能想要一个参数列表,比如
(\ul

接受的答案是有问题的,因为当涉及类型参数时,或者当应该包括对非标称类型的支持时,它会中断

我使用两个选项更新了示例,为类型列表提供了更简洁的表示法,同时仍然允许使用实际类型的语法

导入haxe.macro.Expr;
使用haxe.macro.Tools;
阶级事务{
公共函数new(){}
}
类其他事物{
公共函数new(){}
}
类TPThing{
公共函数new(){}
}
类TMacroNew{
宏静态函数实例(e:Expr){
var tps=开关e.expr{
案例EParenthesis({expr:ECheckType({u,TPath({params:tps}))}):tps;
案例ENew({params:tps},u2;):tps;
案例:抛出“不支持”;
}
var type_path=[用于(tps中的tp)交换机tp{
病例类型(TPath(tp)):tp;
案例:抛出“不支持”;
}];
var news=[对于(类型_路径中的tp)宏new$tp()];
trace((宏$b{news}).toString());
返回宏$b{news};
}
静态函数main(){
实例((:L));
实例(新L());
}
}
编辑:
L<…>可以是任何有效的类型名。它的唯一用途是允许以有效语法编写逗号分隔的类型列表。由于宏函数将表达式作为参数,因此我们必须使用允许/需要类型的表达式,如:
(\u:T)、new T()、var v:T、function(\u:T):T{}

谢谢,我试试看。仍然在试图找到宏和表达式具体化的方法。有时我觉得我理解它是如何工作的,直到它不知道:)这是我唯一无法用物化来做的事情之一。很好!你需要将完整路径传递给宏,对吗?是的,这个答案不会解析类型参数,也不会解析不完全限定的类型-我相信这是可以添加的。在获得这些信息后,我意识到我不想要宏(如果语法更奇怪),但我会手工写出它。哈,所以有一种具体化的方法——我更新了我的回复,甚至找到了保持语法干净的方法!我认为文档可以在此基础上进行改进,我看到这里的具体化方法,它只说
函数$name(){}
,您可以从中猜出语法的存在。谢谢您的添加!在这种情况下,
L
到底是什么?L没有被使用-你可以为一个类型使用任何可能的有效名称。或者,您可以强制使用特定的n