Skip to content

Instantly share code, notes, and snippets.

@skial
Last active December 3, 2018 15:23
Show Gist options
  • Select an option

  • Save skial/5764049 to your computer and use it in GitHub Desktop.

Select an option

Save skial/5764049 to your computer and use it in GitHub Desktop.
Get function name in 3 different ways, each in increasing amounts of magic.
package example.methodName;
import haxe.macro.Printer;
import haxe.macro.Type;
import haxe.macro.Expr;
import haxe.macro.Context;
/**
* ...
* @author Skial Bainn
*/
class Macro {
public static function build():Array<Field> {
var cls = Context.getLocalClass().get();
var fields = Context.getBuildFields();
for (field in fields) {
switch (field.kind) {
case FFun(f):
f.expr = loop( f.expr );
case _:
}
}
return fields;
}
private static function loop(e:Expr):Expr {
var result = e;
switch (e.expr) {
case EVars(vars):
var nvars = [];
for (v in vars) {
if (v.expr != null) v.expr = loop( v.expr );
nvars.push( v );
}
result.expr = EVars( nvars );
case ECall(expr, params):
result.expr = ECall( loop( expr ), [for (p in params) loop( p ) ] );
case EMeta(meta, expr):
var name = new Printer().printExpr( expr );
result = macro new Callback2( { method:$expr, name:$v{name} } );
case EBlock(exprs):
result.expr = EBlock( [for (ex in exprs) loop(ex)] );
case _:
}
return result;
}
}
package example.methodName;
using Reflect;
@:autoBuild( example.methodName.Macro.build() )
interface MethodName {}
class Main implements MethodName {
public static function main() {
// Using reflection
var obj:Dynamic = something;
trace( methodName( Main, obj ) );
obj();
// Using an abstract type
var cb1:Callback1 = something;
trace( cb1.name(Main) );
untyped cb1(); // Callback1 cant call `this`, compiler doesnt allow it.
// Using an abstract type and the macro interface MethodName
var cb2:Callback2 = @:cb something;
trace( cb2.name );
cb2.call(); // Only way to call the original method, as far as I know.
}
public static function something():Void {
trace('Hello World');
}
public static function methodName(cls:Class<Dynamic>, obj:Dynamic):String {
var result:String = null;
if (obj.isFunction()) {
for (name in Reflect.fields( cls )) {
var field:Dynamic = Reflect.field( cls, name );
if (field.isFunction() && Reflect.compareMethods( obj, field )) {
result = name;
break;
}
}
}
return result;
}
}
abstract Callback1(Void->Void) from Void->Void to Void->Void {
public function name(cls:Class<Dynamic>):String {
var result:String = null;
for (name in Reflect.fields( cls )) {
var field:Dynamic = Reflect.field( cls, name );
if (field.isFunction() && Reflect.compareMethods( this, field )) {
result = name;
break;
}
}
return result;
}
public inline function new(v:Void->Void) {
this = v;
}
}
abstract Callback2( { method:Void->Void, name:String } ) {
public var name(get, never):String;
private inline function get_name():String {
return this.name;
}
public inline function new(v:{method:Void->Void, name:String}) {
this = v;
}
public inline function call():Void {
return this.method();
}
}
(function () { "use strict";
var Reflect = function() { }
Reflect.__name__ = true;
Reflect.field = function(o,field) {
var v = null;
try {
v = o[field];
} catch( e ) {
}
return v;
}
Reflect.fields = function(o) {
var a = [];
if(o != null) {
var hasOwnProperty = Object.prototype.hasOwnProperty;
for( var f in o ) {
if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) a.push(f);
}
}
return a;
}
Reflect.isFunction = function(f) {
return typeof(f) == "function" && !(f.__name__ || f.__ename__);
}
Reflect.compareMethods = function(f1,f2) {
if(f1 == f2) return true;
if(!Reflect.isFunction(f1) || !Reflect.isFunction(f2)) return false;
return f1.scope == f2.scope && f1.method == f2.method && f1.method != null;
}
var example = {}
example.methodName = {}
example.methodName.MethodName = function() { }
example.methodName.MethodName.__name__ = true;
example.methodName.Main = function() { }
example.methodName.Main.__name__ = true;
example.methodName.Main.__interfaces__ = [example.methodName.MethodName];
example.methodName.Main.main = function() {
var obj = example.methodName.Main.something;
console.log(example.methodName.Main.methodName(example.methodName.Main,obj));
obj();
var cb1 = example.methodName.Main.something;
console.log(example.methodName._Main.Callback1_Impl_.$name(cb1,example.methodName.Main));
cb1();
var cb2 = { method : example.methodName.Main.something, name : "something"};
console.log(cb2.name);
cb2.method();
}
example.methodName.Main.something = function() {
console.log("Hello World");
}
example.methodName.Main.methodName = function(cls,obj) {
var result = null;
if(Reflect.isFunction(obj)) {
var _g = 0, _g1 = Reflect.fields(cls);
while(_g < _g1.length) {
var name = _g1[_g];
++_g;
var field = Reflect.field(cls,name);
if(Reflect.isFunction(field) && Reflect.compareMethods(obj,field)) {
result = name;
break;
}
}
}
return result;
}
example.methodName._Main = {}
example.methodName._Main.Callback1_Impl_ = function() { }
example.methodName._Main.Callback1_Impl_.__name__ = true;
example.methodName._Main.Callback1_Impl_.$name = function(this1,cls) {
var result = null;
var _g = 0, _g1 = Reflect.fields(cls);
while(_g < _g1.length) {
var name = _g1[_g];
++_g;
var field = Reflect.field(cls,name);
if(Reflect.isFunction(field) && Reflect.compareMethods(this1,field)) {
result = name;
break;
}
}
return result;
}
String.__name__ = true;
Array.__name__ = true;
example.methodName.Main.main();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment