diff --git a/src/tink/macro/Bouncer.hx b/src/tink/macro/Bouncer.hx index 10aa59b..99a20ba 100644 --- a/src/tink/macro/Bouncer.hx +++ b/src/tink/macro/Bouncer.hx @@ -3,7 +3,7 @@ package tink.macro; #if macro import haxe.macro.Context; import haxe.macro.Expr; - + using tink.macro.Positions; using tink.macro.Exprs; #end @@ -15,7 +15,7 @@ package tink.macro; static public function bounceExpr(e:Expr, transform:Expr->Expr) { var id = idCounter++, pos = e.pos; - outerMap.set(id, transform); + outerMap.set(id, transform); return macro @:pos(e.pos) tink.macro.Bouncer.catchBounceExpr($e, $v{id}); } static public function bounce(f:Void->Expr, ?pos:Position) { @@ -29,35 +29,41 @@ package tink.macro; pos = e.pos; outerMap.set(id, transform); return macro @:pos(e.pos) tink.macro.Bouncer.makeOuter($e).andBounce($v{id}); - } + } static function doOuter(id:Int, e:Expr) { return - if (outerMap.exists(id)) + if (outerMap.exists(id)) outerMap.get(id)(e); else - Context.currentPos().error('unknown id ' + id); + Context.currentPos().error('unknown id ' + id); } static function doBounce(id:Int) { return - if (bounceMap.exists(id)) + if (bounceMap.exists(id)) bounceMap.get(id)(); else - Context.currentPos().error('unknown id ' + id); + Context.currentPos().error('unknown id ' + id); } + static public var lastEvaled(default, null):Dynamic; #else - @:noUsing static public function makeOuter(a:A):Bouncer + @:noUsing static public function makeOuter(a:A):Bouncer return null; #end - @:noUsing macro public function andBounce(ethis:Expr, id:Int) + @:noUsing macro public function andBounce(ethis:Expr, id:Int) return switch (ethis.expr) { case ECall(_, params): doOuter(id, params[0]); default: ethis.reject(); } - @:noUsing macro static public function catchBounce(id:Int) + @:noUsing static public macro function eval(f:Void->Dynamic) { + lastEvaled = f(); + return macro null; + } + + @:noUsing macro static public function catchBounce(id:Int) return doBounce(id); - + @:noUsing macro static public function catchBounceExpr(e:Expr, id:Int) return doOuter(id, e); } \ No newline at end of file diff --git a/src/tink/macro/Exprs.hx b/src/tink/macro/Exprs.hx index b7ea55e..480bdc5 100644 --- a/src/tink/macro/Exprs.hx +++ b/src/tink/macro/Exprs.hx @@ -48,6 +48,11 @@ class Exprs { static public inline function as(e:Expr, c:ComplexType) return ECheckType(e, c).at(e.pos); + static public function eval(e:Expr):Dynamic { + Context.typeof(macro tink.macro.Bouncer.eval(function () return $e)); + return Bouncer.lastEvaled; + } + static public function finalize(e:Expr, ?nuPos:Position, ?rules:Dict, ?skipFields = false, ?callPos:PosInfos) { if (nuPos == null) nuPos = Context.currentPos(); diff --git a/src/tink/macro/TypedExprs.hx b/src/tink/macro/TypedExprs.hx index 88bced6..4e3db6d 100644 --- a/src/tink/macro/TypedExprs.hx +++ b/src/tink/macro/TypedExprs.hx @@ -1,5 +1,6 @@ package tink.macro; +import haxe.macro.Context; import haxe.macro.Type; import haxe.ds.Option; using haxe.macro.Tools; @@ -31,6 +32,9 @@ class TypedExprs { return None; } + static public function eval(t:TypedExpr) + return Exprs.eval(Context.storeTypedExpr(t)); + static public function isThis(t:TypedExpr):Bool return switch t { case null: false; diff --git a/tests/Exprs.hx b/tests/Exprs.hx index 8cf88b4..f74abd3 100644 --- a/tests/Exprs.hx +++ b/tests/Exprs.hx @@ -16,38 +16,46 @@ class Exprs extends Base { assertTrue(id.length <= 3); } } + + function testEval() { + var expr = macro (untyped {foo:[{bar:234},'bar']}); + var str = Std.string(untyped {foo:[{bar:234},'bar']}); + assertEquals(Std.string(expr.eval()), Std.string(untyped {foo:[{bar:234},'bar']})); + assertEquals(Std.string(Context.typeExpr(expr).eval()), Std.string(untyped {foo:[{bar:234},'bar']})); + + } function testGet() { assertEquals('foo', (macro foo).getIdent().sure()); assertEquals('foo', (macro "foo").getString().sure()); assertEquals('foo', (macro foo).getName().sure()); assertEquals('foo', (macro "foo").getName().sure()); assertEquals(5, (macro 5).getInt().sure()); - + exprEq(macro [a, b, c], (macro function (a, b, c) [a, b, c]).getFunction().sure().expr); assertEquals('a,b,c', [for (arg in (macro function (a, b, c) [a, b, c]).getFunction().sure().args) arg.name].join(',')); - + assertFalse((macro 'foo').getIdent().isSuccess()); assertFalse((macro foo).getString().isSuccess()); assertFalse((macro 5).getName().isSuccess()); assertFalse((macro 5.1).getInt().isSuccess()); assertFalse((macro foo).getFunction().isSuccess()); } - + function testShortcuts() { assertTrue(true); } - + function testIterType() { assertEquals('Int', (macro [1, 2]).getIterType().sure().getID()); assertEquals('Int', (macro [1, 2].iterator()).getIterType().sure().getID()); assertEquals('Int', ECheckType(macro null, macro: Arrayish).at().getIterType().sure().getID()); } - + function testYield() { function yielder(e) return macro @yield $e; function test(x:Expr, e:Expr, ?options) exprEq(x, e.yield(yielder, options)); - + test(macro @yield foo, macro foo); test(macro @yield (foo), macro (foo)); test(macro for (_) @yield foo, macro for (_) foo); @@ -57,10 +65,10 @@ class Exprs extends Base { } function testSubstitute() { exprEq( - macro foo.call(arg1, arg2), + macro foo.call(arg1, arg2), (macro bar.call(x, y)).substitute({ x: macro arg1, y: macro arg2, bar: macro foo }) ); - + exprEq( macro { var x:Map = new Map(), @@ -89,7 +97,7 @@ class Exprs extends Base { ]) ); } - + function testConcat() { exprEq(macro {a; b;}, (macro a).concat(macro b)); exprEq(macro {a; b; c;}, (macro {a; b;}).concat(macro c));