Skip to content

Instantly share code, notes, and snippets.

@zoon
Created March 23, 2011 03:22
Show Gist options
  • Save zoon/882558 to your computer and use it in GitHub Desktop.
Save zoon/882558 to your computer and use it in GitHub Desktop.
Recursive alpha-renamer for 'this'
package ;
import haxe.macro.Context;
import haxe.macro.Expr;
using Lambda;
class Macros
{
public static var fresh(getFresh, null):String;
private static var _fresh:Int = 0;
private static function getFresh()
{
return "_u" + (_fresh++);
}
private static var _wasThis:Bool;
/**
* Makes thunk (nulary function) from expression. Permits 'this' in expression.
* TODO: add arguments?
* NOTE: practically untested
* @param expression : T
* @return Void -> T
*/
@:macro public static function fn(body:Expr):Expr
{
_wasThis = false;
var fnargs = [];
var pos = Context.currentPos();
var self = fresh;
var thisId = { pos:pos, expr:EConst(CIdent("this")) };
var local = { pos:pos, expr:EVars([ { name:self, type:null, expr:thisId } ]) };
var enew = substExpr(body, self);
var fn = { pos:pos, expr:EFunction( { args:fnargs, ret:null, name:null, expr:enew } ) };
if (_wasThis)
return { pos:pos, expr:EBlock([local, fn]) };
else
return fn;
}
private static function substExpr(?e:Expr, to:String)
{
if (e == null)
return e;
return { expr:substExprDef(e.expr, to), pos:e.pos };
}
private static function substExpArray(es:Array<Expr>, to:String)
{
var result:Array<Expr> = [];
for (e in es)
result.push(substExpr(e, to));
return result;
}
private static function substExprDef(expr:ExprDef, to:String):ExprDef
{
switch (expr)
{
case EConst(c): return expr;
case EArray(e1, e2): return EArray(substExpr(e1,to), substExpr(e2,to));
case EBinop(op , e1, e2): return EBinop(op, substExpr(e1, to), substExpr(e2, to));
case EField(e, field):
switch(e.expr)
{
case EConst(c):
{
if (Type.enumEq(c, CIdent("this")))
{
_wasThis = true;
return EField( { expr:EConst(CIdent(to)), pos:e.pos }, field);
}
else
return EField(substExpr(e, to), field);
}
default:
return EField(substExpr(e, to), field);
}
case EType(e, field): return expr;
case EParenthesis(e): return EParenthesis(substExpr(e,to));
case EObjectDecl(fields): return expr;
case EArrayDecl(values): return EArrayDecl(substExpArray(values, to));
case ECall(e, params): return ECall(substExpr(e, to), substExpArray(params, to));
case ENew( t, params): return ENew(t, substExpArray(params, to));
case EUnop( op, postFix, e): return EUnop(op,postFix,substExpr(e,to));
case EVars(vars): return EVars(Lambda.map(vars, function(v) return
{
name:v.name, type:v.type, expr:substExpr(v.expr, to)
}).array());
case EFunction(f):
return EFunction( { ret:f.ret, name:f.name, args:f.args, expr:substExpr(f.expr, to) } );
case EBlock( exprs): return EBlock(substExpArray(exprs, to));
case EFor(v, it, expr):
return EFor(v, substExpr(it, to), substExpr(expr, to));
case EIf( econd, eif, eelse):
return EIf(substExpr(econd, to), substExpr(eif, to), substExpr(eelse, to));
case EWhile( econd, e, normalWhile):
return EWhile(substExpr(econd, to), substExpr(e, to), normalWhile);
case ESwitch(e, cases, edef):
return ESwitch(substExpr(e, to), Lambda.map(cases , function(v) return
{
values:substExpArray(v.values, to),
expr:substExpr(v.expr, to)
}).array(), substExpr(edef, to));
case ETry(e, catches):
return ETry(substExpr(e, to), Lambda.map(catches, function(v) return
{
name:v.name,type:v.type, expr:substExpr(v.expr, to)
}).array());
case EReturn(e): return EReturn(substExpr(e,to));
case EBreak: return expr;
case EContinue: return expr;
case EUntyped(e): return EUntyped(substExpr(e, to));
case EThrow(e): return EThrow(substExpr(e, to));
case ECast(e, t): return ECast(substExpr(e, to), t);
case EDisplay(e, isCall): return EDisplay(substExpr(e, to), isCall);
case EDisplayNew(t): return expr;
case ETernary(econd, eif, eelse):
return ETernary(substExpr(econd, to), substExpr(eif, to), substExpr(eelse, to));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment