Macro: how to define function arguments using reification inside genericBuild (for type params)

64 views
Skip to first unread message

Thomas John

unread,
Mar 30, 2017, 9:53:20 PM3/30/17
to Haxe
Hi everyone,

I've been searching for a long time now and can't find the solution to that problem. I'm very new to macros but here is where I got so far: http://try-haxe.mrcdk.com/#95c19

What I'm trying to do is to "map" each "type" of a type param like this : Float->Bool->String (in var s:Signal<Float->Bool->String> = new Signal<Float->Bool->String>();) into arguments of a function so, in the end, the function looks like this:

function dispatch(v0:Float, v1:Bool):Void (I'm intentionally omitting the ret type String, but if you know how to do that too, I'll be happy too :))
{
callback(v0, v1);
}

I you look at the try haxe, all the classes and macro are ready. I'm just blocked at defining the args of the function and the variables to the call to callback(...) inside that function.

In case you don't want to check the try haxe example, here are the classes:
class Test {

  public static function main() {
    new Test();
  }
 
  public function new()
  {
    var s:Signal<Float->Bool->String> = new Signal<Float->Bool->String>();
    s.setCallback(signalCallback);
    s.dispatch(5, true);
  }
 
  private function signalCallback(a:Float, b:Bool):String
  {
    trace("signalCallback", a, b);
    return "s";
  }
}

@:genericBuild(Macro.build())
class Signal<SignalFunctionType>
{
    public function new()
    {
   
    }
}

and the macro:

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

using haxe.macro.Tools;

//use this for macros or other classes
class Macro {
  public static var cache = new Map<String, Bool>();
 
    static public function build() {
   
    // getting params
    return switch(Context.getLocalType())
    {
        case TInst(_.get() => { name: "Signal" }, params):
            buildClass(params);

        case t:
            throw 'Incompatible type: $t';
    }
  }
   
  public static function buildClass(params:Array<Type>):ComplexType
  {
    var typeArgsString:Array<String> = new Array();
    var typeArgsT = [];
    var totalTypeArgs:String = "";
    var res:String;
   
    // getting each part of the function definition
    switch (params[0])
    {
      case TFun(args, ret):
        var res;
        // function def arguments
        for(arg in args)
        {
          trace(arg);
          res = Reflect.field(arg.t, "args")[0];
            typeArgsT.push({name:res, type:arg.t, opt:false, value:null});
          typeArgsString.push(res);
          totalTypeArgs += res + "->";
        }
            // function def return argument
        res = Reflect.field(ret, "args")[0];
        totalTypeArgs += res;
        typeArgsString.push(res);

      default:
    }
     
    // new class name
      var className:String = "Signal" + typeArgsString.join("");

    trace(typeArgsT);
    trace(typeArgsString);
    trace(totalTypeArgs);
    trace(className);
  
 
    var pos = Context.currentPos();
    var finalParams = params[0].toComplexType();

    if (!cache.exists(className))
    {
      var dispatchArgs = [for(i in 0...typeArgsString.length - 1) macro $i{"v" + i}];
      var finalDispatchArgs = [for(i in 0...typeArgsString.length - 1) "v" + i].join(", ");
            trace(dispatchArgs);
      trace(finalDispatchArgs);
      var c = macro class $className  
      {
        public var numListeners:Int = 0;
        public var callback:$finalParams;

        public function new()
        {
         
        }

        public function setCallback(callback:$finalParams):Void
        {
          this.callback = callback;
        }

        public function dispatch($a{typeArgsT}):Void
        {
          callback($a{dispatchArgs});
        }
      }

      Context.defineType(c);

      cache[className] = true;
    }
           
           

    return TPath({pack: [], name: className, params: []});
  }
}


Thanks a lot !
Reply all
Reply to author
Forward
0 new messages