2016-05-04 11 views
2

マクロを使用してHaxe関数のパラメータ型を取得し、JNI/Javaメソッドのシグネチャのような短い型の文字列型に変換したいが、戻り型はありません。マクロを使用してHaxe関数のパラメータ型を取得する最適な方法は何ですか?

ここでの動機は、ランタイム時に実行時のタイプ情報をゆっくりと検索することなく、関数のパラメータ型にアクセスできるようにすることです。たとえば、パラメータを取る関数を呼び出すためのグラフィカルウィジェットを構築したいとします。関数に渡す値を調整するのに必要な正しいスピンボックス、テキストボックス、および選択ボックスウィジェットを作成するには、各関数パラメータのタイプが必要です。

Haxe関数のパラメータ型をマクロでどうやって節約できますか?

答えて

3

ここには、いくつかの基本タイプと、それらのタイプに基づく任意の抄録で動作するマクロがあります。関数のパラメータ型を文字列にマップします。例えば、関数型String->Float->Int->String->Voidマップsfisに、ffなどにFloat->Float->Int

package; 

import haxe.macro.Expr; 
import haxe.macro.Context; 
import haxe.macro.Type; 
import haxe.macro.ExprTools; 

// Map some Haxe types to string ids 
@:enum abstract TypeMapping(String) from (String) { 
    var BOOL = "b"; 
    var FLOAT = "f"; 
    var INT = "i"; 
    var STRING = "s"; 
} 

class Util 
{ 
    public macro static function getParameterTypes(f:Expr):ExprOf<String> { 
     var type:Type = Context.typeof(f); 
     if (!Reflect.hasField(type, 'args')) { 
      throw "Parameter has no field 'args'"; 
     } 
     var t = type.getParameters()[0]; 

     var args:Array<Dynamic> = Reflect.field(type, 'args')[0]; 

     var signature:String = ""; 
     for (i in 0...args.length) {    
      switch(args[i].t) { 
       case TAbstract(t, p): 
        var underlyingTypeName = Std.string(t.get().type.getParameters()[0]); 
        switch(underlyingTypeName) { 
         case "Bool": 
          signature += TypeMapping.BOOL; 
         case "Float": 
          signature += TypeMapping.FLOAT; 
         case "Int": 
          signature += TypeMapping.INT; 
         case "String": 
          signature += TypeMapping.STRING; 
         default: 
          throw "Unhandled abstract function parameter type: " + underlyingTypeName; 
        } 
       case CString: 
        signature += TypeMapping.STRING; 
       default: 
        throw "Unhandled function parameter type: " + args[i]; 
      } 
     } 
     return macro $v{signature}; 
    } 
} 

さらなる問題はすべて種類だけではなく、ものを明示的に扱うためにこの仕事を作る方法です。そのためには、各関数パラメータの型名/クラス名/パスをString型の配列に代入し、単一のStringの代わりにその型を返すことがあります。ここではその試みがありますが、まだ関数のパラメータ(おそらく他のもの)では機能しないことに注意してください:

public macro static function getFullParameterTypes(f:Expr):ExprOf<Array<String>> { 
    var type:Type = Context.typeof(f); 
    if (!Reflect.hasField(type, 'args')) { 
     throw "Parameter has no field 'args'"; 
    } 
    var args:Array<Dynamic> = Reflect.field(type, 'args')[0]; 

    var pos = haxe.macro.Context.currentPos(); 
    var signature:Array<Expr> = []; 

    for (i in 0...args.length) { 
     var argType:Type = args[i].t; 
     var s; 
     switch(argType) { 
      case TFun(t, r): 
       s = EConst(CString("Function")); 
       throw "Not working with function parameters yet"; 
      case _: 
       s = EConst(CString(argType.getParameters()[0].toString())); 
     } 
     signature.push({expr: s, pos: pos}); 
    } 
    return macro $a{signature}; 
} 
関連する問題