Created
February 12, 2016 23:26
-
-
Save KeyMaster-/ad55bd7a3e387a531d0f to your computer and use it in GitHub Desktop.
A macro that extracts all static methods from a class that conform to a certain function signature, and returns an array with those functions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import haxe.macro.Expr; | |
import haxe.macro.Context; | |
import haxe.macro.Type; | |
import haxe.macro.TypeTools; | |
import haxe.macro.MacroStringTools; | |
class FunctionFinder { | |
macro public static function get_functions(e:Expr, fun_signature:Expr) { | |
var function_type:Type = switch(fun_signature.expr) { | |
case EConst(c): | |
switch(c) { | |
case CIdent(s): | |
Context.getType(s); | |
default: | |
null; | |
} | |
default: | |
null; | |
} | |
function_type = TypeTools.follow(function_type); | |
var argument_types:Array<Type> = []; | |
var return_type:Type = null; | |
//Check if the type of the signature is actually a function. If so, exctract the argument and return types | |
switch(function_type) { | |
case TFun(args, ret): | |
for(arg in args) { | |
argument_types.push(arg.t); | |
} | |
return_type = ret; | |
default: | |
trace('You did not provide a function typedef!'); | |
return null; | |
} | |
//Get the class type to get fields from later | |
var c:ClassType = null; | |
var def:TypedExprDef = Context.typeExpr(e).expr; | |
var c:ClassType = switch(def){ | |
case TTypeExpr(m): | |
switch(m) { | |
case TClassDecl(c_ref): | |
c_ref.get(); | |
default: | |
null; | |
} | |
default: | |
null; | |
} | |
if(c == null) { | |
trace('You did not provide a class!'); | |
return null; | |
} | |
var functions:Array<Expr> = []; | |
var matching_functions:Array<Expr> = []; | |
for(field in c.statics.get()) { | |
if(field.expr() == null) continue; //If a static method hasn't been typed yet, expr() will return null - Don't know how to wait for all statics to be typed... | |
switch(field.expr().expr) { | |
case TFunction(func): | |
var matches = true; | |
for(i in 0...func.args.length) { | |
//I don't know how to compare types properly, so I hope unification works as well | |
if(!TypeTools.unify(func.args[i].v.t, argument_types[i])) { | |
matches = false; | |
break; | |
} | |
} | |
if(!matches) continue; | |
//Now we know that argument types are the same, test for the return type | |
if(TypeTools.unify(func.expr.t, return_type)) { | |
//Generate the path to the function we're looking at | |
var path = [].concat(c.pack); | |
path.push(c.name); | |
path.push(field.name); | |
functions.push(MacroStringTools.toFieldExpr(path)); | |
} | |
default: | |
} | |
} | |
//Hand-made array declaration containing all our field accesses to functions | |
return { | |
pos:Context.currentPos(), | |
expr:EArrayDecl(functions) | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Main { | |
public static function test(a:Int):Void { | |
trace('test called with: ' + a); | |
} | |
//This function won't be included | |
public static function otherTest(a:String):Void { | |
trace('otherTest called with: ' + a); | |
} | |
public static function main() { | |
var functions:Array<Fun> = FunctionFinder.get_functions(Main, Fun); | |
for(fun in functions) { | |
fun(5); | |
} | |
} | |
} | |
typedef Fun = Int->Void; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment