2015-08-24 3 views
4

Я хочу создать макрос, который генерирует этот код для меня:Как объявить экземпляр в 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) 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 }; 
} 

Эта макрокоманда функция неправильно, я получаю ошибку:

EntityMacroUtils.hx:17: characters 22-43 : Type not found : $componentClass

Проблема заключается в том, что я не знаю, как определить new $componentClass(). Как я могу это решить?

Я также хочу, чтобы не было Type.createInstance в выход код.

ответ

3

Один из способов программно генерировать код Инстанциация с помощью "старой школы" Перечисления AST здание (совместимый Haxe 3.0.1+):

// new pack.age.TheClass() 
return { 
    expr:ENew({name:"TheClass", pack:["pack", "age"], params:[]}, []), 
    pos:Context.currentPos() 
}; 

Усовершенствованный синтаксис с использованием овеществлению можно:

// new pack.age.TheClass() 
var typePath = { name:"TheClass", pack:["pack", "age"], params:[] }; 
return macro new $typePath(); 

Теперь, для удобного синтаксиса функции «вспомогательный экземпляр», нам нужно сделать некоторые контрмеры, чтобы извлечь путь типа из выражения, которое мы получаем в макрофункции:

+0

Спасибо, я попробую это. Все еще пытаюсь найти свой путь с помощью макросов и выражения. Иногда мне кажется, что я понимаю, как это работает, пока это не произойдет :) –

+0

Это одна из единственных вещей, которые я не мог поделать с овеществлением. – Philippe

+0

Хм Я еще не могу понять, как реализовать это в рамках текущей настройки .. –

2

В случае, если кто нуждается в ответах, я получил эту Благодаря ousado на IRC чат Haxe:

Если вы делаете это в одиночку макрос вы можете сделать это:

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 на самом деле не имеет сжатого синтаксиса для типов в позициях выражений. Вы можете передать (_ : TypeName), чтобы предоставить выражение, содержащее ComplexType.

Но если вы хотите, чтобы прохода типа как аргумент, вы могли бы сделать это следующим образом:

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

..ела вы хотите получить список типов, вы можете пойти на список параметров подобный (_ : L< One,Two,Three>).

+0

После получения этой информации я понял, что мне не нужен макрос (если синтаксис более странный), но я просто напишу его вручную. –

+0

Ха, так что есть способ reification - я обновил свой ответ и даже нашел способ сохранить синтаксис чистым! – Philippe

+0

Я думаю, что документы могут быть улучшены на этом, я вижу способы reification здесь http://haxe.org/manual/macro-reification-expression.html, он говорит только 'function $ name() {}', из которого вы могли бы предположим, что синтаксис существует. –

1

Принятый ответ является проблематичным, поскольку он ломается при включении параметров типа или при включении поддержки не номинальных типов.

Я обновил пример, используя две альтернативы для более кратких обозначений для списка типов, сохраняя при этом синтаксис для реальных типов.

import haxe.macro.Expr; 
using haxe.macro.Tools; 

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

class TPThing<T>{ 
    public function new(){} 
} 

class TMacroNew { 

    macro static function instances(e:Expr) { 
     var tps = switch e.expr { 
      case EParenthesis({expr:ECheckType(_,TPath({params:tps}))}):tps; 
      case ENew({params:tps},_):tps; 
      case _: throw "not supported"; 
     } 
     var type_paths = [ for (tp in tps) switch tp { 
      case TPType(TPath(tp)):tp; 
      case _: throw "not supported"; 
     }]; 
     var news = [for (tp in type_paths) macro new $tp()]; 
     trace((macro $b{news}).toString()); 
     return macro $b{news}; 
    } 


    static function main(){ 
     instances((_:L<Thing,Thing,OtherThing,TPThing<Int>>)); 
     instances(new L<Thing,Thing,OtherThing,TPThing<Int>>() ); 
    } 
} 

Edit: The L в L<...> может быть любое допустимое имя типа. Его единственная цель - написать список типов, разделенных запятыми, в действительном синтаксисе. Поскольку макрофункции принимают выражения в качестве аргументов, мы должны использовать выражение, которое позволяет/требует тип, например: (_ :T), new T(), var v:T, function(_:T):T {}.

+0

Спасибо за это дополнение! Что такое 'L' именно в этом случае? –

+0

L не используется - вы можете использовать любое возможное допустимое имя для типа. В качестве альтернативы вы можете принудительно использовать конкретное имя, возможно, что-то описательное, например. 'new FOR_ALL ()'. – ousado

Смежные вопросы