From 0591dc60da018c80596c63ed4d2d769d41043adb Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Thu, 3 Sep 2015 17:24:18 -0700 Subject: [PATCH] Try and make Event more resilient to being accessed from a macro --- lime/app/Event.hx | 189 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 169 insertions(+), 20 deletions(-) diff --git a/lime/app/Event.hx b/lime/app/Event.hx index 6ba01b937..6ee20918a 100644 --- a/lime/app/Event.hx +++ b/lime/app/Event.hx @@ -1,8 +1,16 @@ package lime.app; +#if macro import haxe.macro.Context; import haxe.macro.Expr; +import haxe.macro.Type; +using haxe.macro.Tools; +#end + +#if !macro +@:genericBuild(lime.app.Event.build()) +#end class Event { @@ -16,20 +24,23 @@ class Event { public function new () { - listeners = new Array (); + #if !macro + listeners = new Array (); priorities = new Array (); repeat = new Array (); + #end } public function add (listener:T, once:Bool = false, priority:Int = 0):Void { + #if !macro for (i in 0...priorities.length) { if (priority > priorities[i]) { - listeners.insert (i, listener); + listeners.insert (i, cast listener); priorities.insert (i, priority); repeat.insert (i, !once); return; @@ -38,49 +49,185 @@ class Event { } - listeners.push (listener); + listeners.push (cast listener); priorities.push (priority); repeat.push (!once); + #end } - macro public function dispatch (ethis:Expr, args:Array) { + #if macro + private static function build () { - return macro { + var typeArgs; + var typeResult; + + switch (Context.getLocalType ()) { - var listeners = $ethis.listeners; - var repeat = $ethis.repeat; - var i = 0; + case TInst (_, [ TFun (args, result) ]): + + typeArgs = args; + typeResult = result; + + default: + + throw false; - while (i < listeners.length) { + } + + var typeParam = TFun (typeArgs, typeResult); + var typeString = ""; + + if (typeArgs.length == 0) { + + typeString = "Void->"; + + } else { + + for (arg in typeArgs) { - listeners[i] ($a{args}); - - if (!repeat[i]) { - - $ethis.remove (listeners[i]); - - } else { - - i++; - - } + typeString += arg.t.toString () + "->"; } } + typeString += typeResult.toString (); + + var name = "Event$" + StringTools.replace (StringTools.replace (typeString, ".", "_"), "->", "__"); + + try { + + Context.getType ("lime.app." + name); + + } catch (e:Dynamic) { + + var pos = Context.currentPos (); + var fields = Context.getBuildFields (); + + var args = []; + var argName; + var argNames = []; + var argString = ""; + var i = 0; + + for (arg in typeArgs) { + + if (i == 0) { + + argName = "arg"; + argString = argName; + + } else { + + argName = "arg" + i; + argString += ", " + argName; + + } + + argNames.push (Context.parse (argName, pos)); + + i++; + + args.push ({ name: argName, type: arg.t.toComplexType () }); + + } + + var dispatch = macro { + + var listeners = this.listeners; + var repeat = this.repeat; + var i = 0; + + while (i < listeners.length) { + + listeners[i] ($a{argNames}); + + if (!repeat[i]) { + + this.remove (cast listeners[i]); + + } else { + + i++; + + } + + } + + } + + for (field in fields) { + + if (field.name == "listeners") { + + fields.remove (field); + break; + + } + + } + + fields.push ( { name: "listeners", access: [ APublic ], kind: FVar (TPath ({ pack: [], name: "Array", params: [ TPType (typeParam.toComplexType ()) ] })), pos: pos } ); + fields.push ( { name: "dispatch", access: [ APublic ], kind: FFun ( { args: args, expr: dispatch, params: [], ret: macro :Void } ), pos: pos } ); + + Context.defineType ({ + pos: pos, + pack: [ "lime", "app" ], + name: name, + kind: TDClass (), + fields: fields, + params: [ { name: "T" } ], + meta: [ ] + }); + + } + + return TPath ( { pack: [ "lime", "app" ], name: name, params: [ TPType (typeParam.toComplexType ()) ] } ); + } + #end + + + //macro public function dispatch (ethis:Expr, args:Array):Void { + // + //return macro { + // + //var listeners = $ethis.listeners; + //var repeat = $ethis.repeat; + //var i = 0; + // + //while (i < listeners.length) { + // + //listeners[i] ($a{args}); + // + //if (!repeat[i]) { + // + //$ethis.remove (listeners[i]); + // + //} else { + // + //i++; + // + //} + // + //} + // + //} + // + //} public function has (listener:T):Bool { + #if !macro for (l in listeners) { if (Reflect.compareMethods (l, listener)) return true; } + #end return false; @@ -89,6 +236,7 @@ class Event { public function remove (listener:T):Void { + #if !macro var i = listeners.length; while (--i >= 0) { @@ -102,6 +250,7 @@ class Event { } } + #end }