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