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/#95c19What 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 !