Add eval to Expr/TypedExpr.

This commit is contained in:
Juraj Kirchheim
2021-06-02 10:21:41 +02:00
parent 40d7c2fbde
commit aa186a1ec2
4 changed files with 43 additions and 20 deletions

View File

@@ -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:A):Bouncer
@:noUsing static public function makeOuter<A>(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);
}

View File

@@ -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<String>, ?skipFields = false, ?callPos:PosInfos) {
if (nuPos == null)
nuPos = Context.currentPos();

View File

@@ -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;

View File

@@ -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<Int, String> = 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));