with() {...}
好的,这是在 Haxe 上实现一个非常简单的仿真的代码:
//simple.hx
class Simple
{
@:macro public static function with(subject:Expr, block:Expr)
{
return with_impl(subject, block);
}
#if macro
static function with_impl(subject:Expr, block:Expr)
{
function mk(e, pos) return { expr:e, pos:pos };
//this is the main function here. It's going to find a variable the expression so it uses our subject
function changeIdent(identExpr:Expr, changeExpr)
{
return switch(identExpr.expr)
{
case EConst(c):
switch(c)
{
case CIdent(s):
mk(EField(changeExpr, s), identExpr.pos);
default:
identExpr;
}
case EField(e, f):
mk(EField(changeIdent(e, changeExpr), f), identExpr.pos);
case EType(e, f):
mk(EType(changeIdent(e, changeExpr), f), identExpr.pos);
default: //fallba
identExpr;
}
}
return switch(block.expr)
{
case EBlock(exprs):
var newblock = [];
for (statement in exprs)
{
switch(statement.expr)
{
case ECall(e, params):
newblock.push(mk(ECall(changeIdent(e, subject), params), statement.pos));
default:
newblock.push(statement);
}
}
mk(EBlock(newblock), block.pos);
case EDisplay(e, iscall):
mk(EDisplay(with_impl(subject, e), iscall), block.pos);
default:
changeIdent(block, subject);
}
}
#end
}
你像这样使用它:
//Main.hx
class Main
{
static function main()
{
Simple.with (Lib.current.graphics,
{
beginFill(0xC0FFEE, 1);
drawRect( -10, -10, 20, 20 );
endFill();
});
}
}
它不会改变作用域,而是寻找调用表达式,然后将函数(主题)的第一个参数添加到每个表达式中。所以上面的代码等价于:
{
Lib.current.graphics.beginFill(0xC0FFEE, 1);
Lib.current.graphics.drawRect( -10, -10, 20, 20 );
Lib.current.graphics.endFill();
}
宏太有趣了!