New facade. Rudimentary tests.
This commit is contained in:
@@ -5,7 +5,7 @@ import haxe.macro.Type;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Printer;
|
||||
|
||||
using tink.macro.Tools;
|
||||
using tink.Macro;
|
||||
using Lambda;
|
||||
|
||||
class ClassBuilder {
|
||||
|
||||
@@ -2,7 +2,7 @@ package tink.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using tink.macro.Tools;
|
||||
using tink.Macro;
|
||||
|
||||
class Constructor {
|
||||
var oldStatements:Array<Expr>;
|
||||
@@ -12,6 +12,7 @@ class Constructor {
|
||||
var afterArgs:Array<FunctionArg>;
|
||||
var pos:Position;
|
||||
var onGenerateHooks:Array<Function->Void>;
|
||||
var superCall:Expr;
|
||||
public var isPublic:Null<Bool>;
|
||||
|
||||
public function new(f:Function, ?isPublic:Null<Bool> = null, ?pos:Position) {
|
||||
@@ -43,6 +44,12 @@ class Constructor {
|
||||
default: oldStatements = [f.expr];
|
||||
}
|
||||
}
|
||||
superCall =
|
||||
if (oldStatements.length == 0) [].toBlock();
|
||||
else switch oldStatements[0] {
|
||||
case macro super($a{_}): oldStatements.shift();
|
||||
default: [].toBlock();
|
||||
}
|
||||
}
|
||||
public function addStatement(e:Expr, ?prepend)
|
||||
if (prepend)
|
||||
@@ -68,7 +75,7 @@ class Constructor {
|
||||
isPublic = true;
|
||||
|
||||
function toBlock()
|
||||
return nuStatements.concat(oldStatements).toBlock(pos);
|
||||
return [superCall].concat(nuStatements).concat(oldStatements).toBlock(pos);
|
||||
|
||||
public function onGenerate(hook)
|
||||
this.onGenerateHooks.push(hook);
|
||||
|
||||
@@ -24,15 +24,9 @@ typedef ParamSubst = {
|
||||
|
||||
class Exprs {
|
||||
|
||||
static public inline function is(e:Expr, c:ComplexType) {
|
||||
static public inline function is(e:Expr, c:ComplexType)
|
||||
return ECheckType(e, c).at(e.pos).typeof().isSuccess();
|
||||
}
|
||||
static var annotCounter = 0;
|
||||
static var annotations = new Map<Int,Dynamic>();
|
||||
static public function tag<D>(e:Expr, data:D) {
|
||||
annotations.set(annotCounter, data);
|
||||
return [(annotCounter++).toExpr(e.pos), e].toBlock(e.pos);
|
||||
}
|
||||
|
||||
static public function finalize(e:Expr, ?nuPos:Position, ?rules:Dynamic<String>, ?skipFields = false, ?callPos:PosInfos) {
|
||||
if (nuPos == null)
|
||||
nuPos = Context.currentPos();
|
||||
@@ -43,7 +37,7 @@ class Exprs {
|
||||
if (Reflect.hasField(rules, s))
|
||||
Reflect.field(rules, s)
|
||||
else if (s.startsWith('tmp')) {
|
||||
Reflect.setField(rules, s, Tools.tempName(String, '__tink' + s.substr(3)));
|
||||
Reflect.setField(rules, s, Macro.tempName(String, '__tink' + s.substr(3)));
|
||||
replace(s);
|
||||
}
|
||||
else s;
|
||||
@@ -80,14 +74,8 @@ class Exprs {
|
||||
}
|
||||
});
|
||||
}
|
||||
static public function untag<D>(e:Expr):{data:D, e:Expr } {
|
||||
return
|
||||
switch (e.expr) {
|
||||
case EBlock(exprs): { e: exprs[1], data: annotations.get(exprs[0].getInt().sure()) };
|
||||
default: e.reject();
|
||||
}
|
||||
}
|
||||
static public function withPrivateAccess(e:Expr) {
|
||||
|
||||
static public function withPrivateAccess(e:Expr)
|
||||
return
|
||||
e.transform(function (e:Expr)
|
||||
return
|
||||
@@ -97,13 +85,10 @@ class Exprs {
|
||||
default: e;
|
||||
}
|
||||
);
|
||||
}
|
||||
static public function getPrivate(e:Expr, field:String, ?pos) {
|
||||
return EMeta( { name: ':privateAccess', params: [], pos: pos }, e.field(field, pos)).at(pos);
|
||||
}
|
||||
static public function partial<D>(c:ComplexType, data:D, ?pos)
|
||||
return ECheckType(macro null, c).at(pos).tag(data);
|
||||
|
||||
|
||||
static public function getPrivate(e:Expr, field:String, ?pos:Position)
|
||||
return macro @:pos(pos.sanitize()) @:privateAccess $e.$field;
|
||||
|
||||
static public function substitute(source:Expr, vars:Dynamic<Expr>, ?pos)
|
||||
return
|
||||
transform(source, function (e:Expr) {
|
||||
@@ -120,8 +105,10 @@ class Exprs {
|
||||
|
||||
static public inline function ifNull(e:Expr, fallback:Expr)
|
||||
return
|
||||
if (e.getIdent().equals('null')) fallback;
|
||||
else e;
|
||||
switch e {
|
||||
case macro null: fallback;
|
||||
default: e;
|
||||
}
|
||||
|
||||
static public function substParams(source:Expr, subst:ParamSubst, ?pos):Expr
|
||||
return crawl(
|
||||
@@ -130,10 +117,8 @@ class Exprs {
|
||||
function (c:ComplexType)
|
||||
return
|
||||
switch (c) {
|
||||
case TPath(p):
|
||||
if (p.pack.length == 0 && subst.exists(p.name))
|
||||
subst.get(p.name);
|
||||
else c;
|
||||
case TPath({ pack: [], name: name }) if (subst.exists(name)):
|
||||
subst.get(name);
|
||||
default: c;
|
||||
}
|
||||
, pos);
|
||||
@@ -141,35 +126,32 @@ class Exprs {
|
||||
static public function transform(source:Expr, transformer:Expr->Expr, ?pos):Expr
|
||||
return crawl(source, transformer, function (t) return t, pos);
|
||||
|
||||
static function crawlArray(a:Array<Dynamic>, transformer:Expr->Expr, retyper:ComplexType-> ComplexType, pos:Position):Array<Dynamic> {
|
||||
if (a == null) return a;
|
||||
var ret = [];
|
||||
for (v in a)
|
||||
ret.push(crawl(v, transformer, retyper, pos));
|
||||
return ret;
|
||||
}
|
||||
static function crawlArray(a:Array<Dynamic>, transformer:Expr->Expr, retyper:ComplexType-> ComplexType, pos:Position):Array<Dynamic>
|
||||
return
|
||||
if (a == null) a;
|
||||
else
|
||||
[for (v in a)
|
||||
crawl(v, transformer, retyper, pos)
|
||||
];
|
||||
|
||||
static public function getIterType(target:Expr)
|
||||
return
|
||||
(macro {
|
||||
(macro @:pos(target.pos) {
|
||||
var t = null,
|
||||
target = $target;
|
||||
for (i in target)
|
||||
t = i;
|
||||
t;
|
||||
}).finalize(target.pos).typeof();
|
||||
}).typeof();
|
||||
|
||||
static public function yield(e:Expr, yielder:Expr->Expr):Expr {
|
||||
inline function rec(e)
|
||||
return yield(e, yielder);
|
||||
return
|
||||
if (e == null) null;
|
||||
else if (e.expr == null) e;
|
||||
if (e == null || e.expr == null) e;
|
||||
else switch (e.expr) {
|
||||
case EVars(_):
|
||||
(macro @:pos(e.pos) var x = { var x = 5; } ).typeof().sure();
|
||||
throw 'unreachable';//the above should cause an error
|
||||
case EParenthesis(e):
|
||||
EParenthesis(rec(e)).at(e.pos);
|
||||
e.pos.error('Variable declaration not supported here');
|
||||
case EBlock(exprs) if (exprs.length > 0):
|
||||
exprs = exprs.copy();
|
||||
exprs.push(rec(exprs.pop()));
|
||||
@@ -186,12 +168,6 @@ class Exprs {
|
||||
EFor(it, rec(expr)).at(e.pos);
|
||||
case EWhile(cond, body, normal):
|
||||
EWhile(cond, rec(body), normal).at(e.pos);
|
||||
case ECheckType(e, t):
|
||||
ECheckType(rec(e), t).at(e.pos);
|
||||
case EMeta(s, e):
|
||||
EMeta(s, rec(e)).at(e.pos);
|
||||
case EUntyped(e):
|
||||
EUntyped(rec(e)).at(e.pos);
|
||||
case EBreak, EContinue: e;
|
||||
case EBinop(OpArrow, value, jump) if (jump.expr == EContinue || jump.expr == EBreak):
|
||||
macro @:pos(e.pos) {
|
||||
@@ -202,7 +178,7 @@ class Exprs {
|
||||
}
|
||||
}
|
||||
|
||||
static function crawl(target:Dynamic, transformer:Expr->Expr, retyper:ComplexType->ComplexType, pos:Position):Dynamic {
|
||||
static function crawl(target:Dynamic, transformer:Expr->Expr, retyper:ComplexType->ComplexType, pos:Position):Dynamic
|
||||
return
|
||||
if (Std.is(target, Array))
|
||||
crawlArray(target, transformer, retyper, pos);
|
||||
@@ -210,13 +186,13 @@ class Exprs {
|
||||
switch (Inspect.typeof(target)) {
|
||||
case TNull, TInt, TFloat, TBool, TFunction, TUnknown, TClass(_): target;
|
||||
case TEnum(e):
|
||||
if (Inspect.getEnum(target) == ComplexType) return retyper(target);
|
||||
else {
|
||||
// if (Inspect.getEnum(target) == ComplexType) return retyper(target);
|
||||
// else {
|
||||
var ret:Dynamic = Inspect.createEnumIndex(e, Inspect.enumIndex(target), crawlArray(Inspect.enumParameters(target), transformer, retyper, pos));
|
||||
return
|
||||
if (Inspect.getEnum(ret) == ComplexType) retyper(ret);
|
||||
else ret;
|
||||
}
|
||||
// }
|
||||
case TObject:
|
||||
var ret:Dynamic = { };
|
||||
for (field in Reflect.fields(target))
|
||||
@@ -227,13 +203,17 @@ class Exprs {
|
||||
}
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO: this whole thing needs an overhaul
|
||||
static public function typedMap(source:Expr, f:Expr->Array<VarDecl>->Expr, ctx:Array<VarDecl>, ?pos:Position):Expr {
|
||||
if (ctx == null) ctx = [];
|
||||
|
||||
function rec(e, ?inner)
|
||||
return typedMap(e, f, inner == null ? ctx : inner, pos);
|
||||
|
||||
function def(name:String, ?e:Expr, ?t:ComplexType)
|
||||
return { name: name, expr: e, type: t };
|
||||
|
||||
if (source == null || source.expr == null) return source;
|
||||
var mappedSource = f(source, ctx);
|
||||
if (mappedSource != source) return mappedSource;
|
||||
@@ -260,10 +240,10 @@ class Exprs {
|
||||
case ENew(t, params): ENew(t, params.typedMapArray(f, ctx, pos));
|
||||
case EBinop(op, e1, e2): EBinop(op, rec(e1), rec(e2));
|
||||
case EObjectDecl(fields):
|
||||
var newFields = [];
|
||||
for (field in fields)
|
||||
newFields.push( { field:field.field, expr:rec(field.expr) } );
|
||||
EObjectDecl(newFields);
|
||||
EObjectDecl([for (field in fields) {
|
||||
field: field.field,
|
||||
expr: rec(field.expr)
|
||||
}]);
|
||||
case ESwitch(expr, cases, def):
|
||||
var newCases = cases;
|
||||
newCases = [];
|
||||
@@ -309,12 +289,11 @@ class Exprs {
|
||||
newCases.push( { expr: rec(c.expr, innerCtx), values: caseValues } );
|
||||
}
|
||||
case _:
|
||||
for (c in cases) {
|
||||
var caseValues = [];
|
||||
for (v in c.values)
|
||||
caseValues.push(rec(v));
|
||||
newCases.push( { expr: rec(c.expr), values: caseValues } );
|
||||
}
|
||||
for (c in cases)
|
||||
newCases.push({
|
||||
expr: rec(c.expr),
|
||||
values: [for (v in c.values) rec(v)]
|
||||
});
|
||||
}
|
||||
ESwitch(expr, newCases, rec(def));
|
||||
case EFor(it, expr):
|
||||
@@ -336,24 +315,21 @@ class Exprs {
|
||||
Context.error("Internal error in " + mappedSource.toString(), mappedSource.pos);
|
||||
}
|
||||
case ETry(e, catches):
|
||||
var newCatches = [];
|
||||
for (c in catches)
|
||||
{
|
||||
var innerCtx = ctx.copy();
|
||||
innerCtx.push({ name:c.name, expr: null, type:c.type });
|
||||
newCatches.push({name:c.name, expr:rec(c.expr, innerCtx), type:c.type});
|
||||
}
|
||||
ETry(rec(e), newCatches);
|
||||
ETry(
|
||||
rec(e),
|
||||
[for (c in catches) {
|
||||
name: c.name,
|
||||
expr: rec(c.expr, ctx.concat([def(c.name, c.type)])),
|
||||
type: c.type
|
||||
}]
|
||||
);
|
||||
case EFunction(name, func):
|
||||
var innerCtx = ctx.copy();
|
||||
for (arg in func.args)
|
||||
innerCtx.push( { name:arg.name, type:arg.type, expr:null } );
|
||||
func.expr = rec(func.expr, innerCtx);
|
||||
func.expr = rec(func.expr, ctx.concat([for (arg in func.args) def(arg.name, arg.type)]));
|
||||
EFunction(name, func);
|
||||
case EVars(vars):
|
||||
//This is incorrect. When declaring multiple variables, they are declared in the previous context "at once"
|
||||
var ret = [];
|
||||
for (v in vars)
|
||||
{
|
||||
for (v in vars) {
|
||||
var vExpr = v.expr == null ? null : typedMap(v.expr, f, ctx);
|
||||
if (v.type == null && vExpr != null)
|
||||
v.type = vExpr.typeof(ctx).sure().toComplex();
|
||||
@@ -367,22 +343,16 @@ class Exprs {
|
||||
return ret.at(pos == null ? source.pos : pos);
|
||||
}
|
||||
|
||||
static public function typedMapArray(source:Array<Expr>, f:Expr->Array<VarDecl>->Expr, ctx:Array<VarDecl>, ?pos) {
|
||||
var ret = [];
|
||||
for (e in source)
|
||||
ret.push(typedMap(e, f, ctx, pos));
|
||||
return ret;
|
||||
}
|
||||
static public function typedMapArray(source:Array<Expr>, f:Expr->Array<VarDecl>->Expr, ctx:Array<VarDecl>, ?pos)
|
||||
return [for (e in source) typedMap(e, f, ctx, pos)];
|
||||
|
||||
static public inline function iterate(target:Expr, body:Expr, ?loopVar:String = 'i', ?pos:Position)
|
||||
return EFor(EIn(loopVar.resolve(pos), target).at(pos), body).at(pos);
|
||||
|
||||
static public function toFields(object:Dynamic<Expr>, ?pos:Position) {
|
||||
var args = [];
|
||||
for (field in Reflect.fields(object))
|
||||
args.push( { field:field, expr: untyped Reflect.field(object, field) } );
|
||||
return EObjectDecl(args).at(pos);
|
||||
}
|
||||
static public function toFields(object:Dynamic<Expr>, ?pos:Position)
|
||||
return EObjectDecl([for (field in Reflect.fields(object))
|
||||
{ field:field, expr: untyped Reflect.field(object, field) }
|
||||
]).at(pos);
|
||||
|
||||
static public inline function log(e:Expr, ?pos:PosInfos):Expr {
|
||||
haxe.Log.trace(e.toString(), pos);
|
||||
@@ -393,13 +363,12 @@ class Exprs {
|
||||
return e.pos.error(reason);
|
||||
|
||||
static public inline function toString(e:Expr):String
|
||||
// return tink.macro.tools.Printer.printExpr('', e);
|
||||
return new haxe.macro.Printer().printExpr(e);
|
||||
|
||||
static public inline function at(e:ExprDef, ?pos:Position)
|
||||
return {
|
||||
expr: e,
|
||||
pos: pos.getPos()
|
||||
pos: pos.sanitize()
|
||||
};
|
||||
|
||||
static public inline function instantiate(s:String, ?args:Array<Expr>, ?params:Array<TypeParam>, ?pos:Position)
|
||||
@@ -427,7 +396,7 @@ class Exprs {
|
||||
return ECall(e, params == null ? [] : params).at(pos);
|
||||
|
||||
static public inline function toExpr(v:Dynamic, ?pos:Position)
|
||||
return Context.makeExpr(v, pos.getPos());
|
||||
return Context.makeExpr(v, pos.sanitize());
|
||||
|
||||
static public inline function toArray(exprs:Iterable<Expr>, ?pos)
|
||||
return EArrayDecl(exprs.array()).at(pos);
|
||||
@@ -452,7 +421,7 @@ class Exprs {
|
||||
static public inline function resolve(s:String, ?pos)
|
||||
return drill(s.split('.'), pos);
|
||||
|
||||
static public function typeof(expr:Expr, ?locals) {
|
||||
static public function typeof(expr:Expr, ?locals)
|
||||
return
|
||||
try {
|
||||
if (locals != null)
|
||||
@@ -466,18 +435,14 @@ class Exprs {
|
||||
catch (e:Dynamic) {
|
||||
expr.pos.makeFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
static public inline function cond(cond:Expr, cons:Expr, ?alt:Expr, ?pos)
|
||||
return EIf(cond, cons, alt).at(pos);
|
||||
|
||||
static public function isWildcard(e:Expr)
|
||||
return
|
||||
switch(e.expr) {
|
||||
case EConst(c):
|
||||
switch (c) {
|
||||
case CIdent(s): s == '_';
|
||||
default: false;
|
||||
}
|
||||
switch e {
|
||||
case macro _: true;
|
||||
default: false;
|
||||
}
|
||||
|
||||
@@ -538,86 +503,4 @@ class Exprs {
|
||||
static inline var NOT_A_STRING = "string constant expected";
|
||||
static inline var NOT_A_NAME = "name expected";
|
||||
static inline var NOT_A_FUNCTION = "function expected";
|
||||
static inline var EMPTY_EXPRESSION = "expression expected";
|
||||
|
||||
static public function match(expr:Expr, pattern:Expr)
|
||||
return new Matcher().match(expr, pattern);
|
||||
|
||||
}
|
||||
|
||||
private class Matcher {
|
||||
var exprs:Dynamic<Expr>;
|
||||
var strings:Dynamic<String>;
|
||||
public function new() {
|
||||
this.exprs = {};
|
||||
this.strings = {};
|
||||
}
|
||||
public function match(expr:Expr, pattern:Expr) {
|
||||
return
|
||||
try {
|
||||
recurse(expr, pattern);
|
||||
Success({
|
||||
exprs: exprs,
|
||||
strings: strings,//TODO: deprecate
|
||||
names: strings,
|
||||
pos: expr.pos
|
||||
});
|
||||
}
|
||||
catch (e:String) Failure(e);
|
||||
}
|
||||
function matchObject(x1:Dynamic, x2:Dynamic) {
|
||||
if (x2 == null) throw Std.string(x2) + ' expected but found ' + Std.string(x1);
|
||||
for (f in Reflect.fields(x1))
|
||||
matchAny(Reflect.field(x1, f), Reflect.field(x2, f));
|
||||
}
|
||||
function matchString(s1:String, s2:String) {
|
||||
if (s2 == null)
|
||||
equal(s1, s2);
|
||||
else if (s2.startsWith('eval__') || s2.startsWith('NAME__'))
|
||||
Reflect.setField(strings, s2.substr(6), s1);
|
||||
else
|
||||
equal(s1, s2);
|
||||
}
|
||||
function equal(x1:Dynamic, x2:Dynamic) {
|
||||
if (x1 != x2) throw Std.string(x2) + ' expected but found ' + Std.string(x1);
|
||||
}
|
||||
function matchAny(x1:Dynamic, x2:Dynamic) {
|
||||
switch (Inspect.typeof(x1)) {
|
||||
case TNull, TInt, TFloat, TBool: equal(x1, x2);
|
||||
case TObject:
|
||||
if (Std.is(x1.expr, ExprDef)) recurse(x1, x2);
|
||||
else matchObject(x1, x2);
|
||||
case TFunction:
|
||||
throw 'unexpected';
|
||||
case TClass(c):
|
||||
if (c == Array) matchArray(x1, x2);
|
||||
else if (c == String) matchString(x1, x2);
|
||||
else throw 'unexpected';
|
||||
case TEnum(_): matchEnum(x1, x2);
|
||||
case TUnknown:
|
||||
}
|
||||
}
|
||||
function matchArray(a1:Array<Dynamic>, a2:Array<Dynamic>) {
|
||||
equal(a1.length, a2.length);
|
||||
for (i in 0...a1.length)
|
||||
matchAny(a1[i], a2[i]);
|
||||
}
|
||||
function matchEnum(e1:Dynamic, e2:Dynamic) {
|
||||
equal(Inspect.enumConstructor(e1), Inspect.enumConstructor(e2));
|
||||
matchArray(Inspect.enumParameters(e1), Inspect.enumParameters(e2));
|
||||
}
|
||||
function recurse(expr:Expr, pattern:Expr) {
|
||||
if (pattern == null) throw 'nothing expected but found ' + expr.toString();
|
||||
switch (pattern.getIdent()) {
|
||||
case Success(s):
|
||||
if (s.startsWith('$'))
|
||||
Reflect.setField(exprs, s.substr(1), expr);
|
||||
else if (s.startsWith('EXPR__'))
|
||||
Reflect.setField(exprs, s.substr(6), expr);
|
||||
else
|
||||
matchEnum(expr.expr, pattern.expr);
|
||||
default:
|
||||
matchEnum(expr.expr, pattern.expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package tink.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
using tink.core.Outcome;
|
||||
using tink.macro.Tools;
|
||||
using tink.Macro;
|
||||
|
||||
abstract Member(Field) from Field to Field {
|
||||
static public function prop(name:String, t:ComplexType, pos, ?noread = false, ?nowrite = false):Member {
|
||||
|
||||
@@ -2,8 +2,7 @@ package tink.macro;
|
||||
|
||||
import haxe.macro.Expr;
|
||||
|
||||
using tink.core.Outcome;
|
||||
using tink.macro.Tools;
|
||||
using tink.Macro;
|
||||
|
||||
class Binary {
|
||||
static public function get(o:Binop, e:Expr)
|
||||
@@ -29,11 +28,10 @@ class Binary {
|
||||
|
||||
static public inline function make(op:Binop, e1:Expr, e2:Expr, ?pos)
|
||||
return Exprs.binOp(e1, e2, op, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Unary {
|
||||
static public function get(o:Unop, e:Expr, postfix:Bool = false) {
|
||||
static public function get(o:Unop, e:Expr, postfix:Bool = false)
|
||||
return
|
||||
switch e.expr {
|
||||
case EUnop(op, postFix, arg):
|
||||
@@ -46,8 +44,8 @@ class Unary {
|
||||
default:
|
||||
e.pos.makeFailure('expected unary operation ' + o);
|
||||
}
|
||||
}
|
||||
static public function getUnop(e:Expr) {
|
||||
|
||||
static public function getUnop(e:Expr)
|
||||
return
|
||||
switch e.expr {
|
||||
case EUnop(op, postFix, arg):
|
||||
@@ -55,8 +53,7 @@ class Unary {
|
||||
default:
|
||||
e.pos.makeFailure('expected unary operation but found ' + Type.enumConstructor(e.expr));
|
||||
}
|
||||
}
|
||||
static public function make(op:Unop, e:Expr, ?postFix = false, ?pos) {
|
||||
|
||||
static public function make(op:Unop, e:Expr, ?postFix = false, ?pos)
|
||||
return EUnop(op, postFix, e).at(pos);
|
||||
}
|
||||
}
|
||||
@@ -2,62 +2,41 @@ package tink.macro;
|
||||
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Expr;
|
||||
|
||||
import tink.core.Error;
|
||||
using tink.macro.Positions;
|
||||
using tink.core.Outcome;
|
||||
|
||||
class Positions {
|
||||
|
||||
static public function getOutcome<D, F>(pos:Position, outcome:Outcome<D, F>):D {
|
||||
static public function getOutcome<D, F>(pos:Position, outcome:Outcome<D, F>):D
|
||||
return
|
||||
switch (outcome) {
|
||||
case Success(d): d;
|
||||
case Failure(f): pos.error(f);
|
||||
}
|
||||
}
|
||||
|
||||
static public function makeBlankType(pos:Position):ComplexType
|
||||
return Types.toComplex(Context.typeof(macro null));
|
||||
return Types.toComplex(Context.typeof(macro @:pos(pos.sanitize()) null));
|
||||
|
||||
static public inline function getPos(pos:Position) {
|
||||
static public inline function sanitize(pos:Position)
|
||||
return
|
||||
if (pos == null)
|
||||
Context.currentPos();
|
||||
else
|
||||
pos;
|
||||
}
|
||||
static public function errorExpr(pos:Position, error:Dynamic) {
|
||||
|
||||
static public function errorExpr(pos:Position, error:Dynamic)
|
||||
return Bouncer.bounce(function ():Expr {
|
||||
return Positions.error(pos, error);
|
||||
}, pos);
|
||||
}
|
||||
static public inline function error(pos:Position, error:Dynamic):Dynamic {
|
||||
return Context.error(Std.string(error), pos);
|
||||
}
|
||||
|
||||
static public inline function error(pos:Position, error:Dynamic):Dynamic
|
||||
return Context.error(Std.string(error), sanitize(pos));
|
||||
|
||||
static public inline function warning<A>(pos:Position, warning:Dynamic, ?ret:A):A {
|
||||
Context.warning(Std.string(warning), pos);
|
||||
return ret;
|
||||
}
|
||||
///used to easily construct failed outcomes
|
||||
static public function makeFailure<A, Reason>(pos:Position, reason:Reason):Outcome<A, MacroError<Reason>> {
|
||||
return Failure(new MacroError(reason, pos));
|
||||
}
|
||||
}
|
||||
|
||||
private class MacroError<Data> implements ThrowableFailure {
|
||||
public var data(default, null):Data;
|
||||
public var pos(default, null):Position;
|
||||
public function new(data:Data, ?pos:Position) {
|
||||
this.data = data;
|
||||
this.pos =
|
||||
if (pos == null)
|
||||
Context.currentPos();
|
||||
else
|
||||
pos;
|
||||
}
|
||||
public function toString() {
|
||||
return 'Error@' + Std.string(pos) + ': ' + Std.string(data);
|
||||
}
|
||||
public function throwSelf():Dynamic {
|
||||
return Context.error(Std.string(data), pos);
|
||||
}
|
||||
static public function makeFailure<A>(pos:Position, reason:String):Outcome<A, Error>
|
||||
return Failure(new Error(reason, pos));
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package tink.macro;
|
||||
|
||||
#if macro
|
||||
import haxe.macro.Context;
|
||||
typedef _Positions = Positions;
|
||||
typedef _ExprTools = haxe.macro.ExprTools;
|
||||
typedef _Exprs = Exprs;
|
||||
typedef _Functions = Functions;
|
||||
typedef _Metadatas = Metadatas;
|
||||
typedef _Bouncer = Bouncer;
|
||||
typedef _Types = Types;
|
||||
typedef _Binops = Ops.Binary;
|
||||
typedef _Unops = Ops.Unary;
|
||||
typedef _Outcomes = tink.core.Outcome.OutcomeTools;
|
||||
#end
|
||||
class Tools {
|
||||
static var idCounter = 0;
|
||||
static public inline function tempName(c:Class<String>, ?prefix = '__tinkTmp'):String {
|
||||
return prefix + Std.string(idCounter++);
|
||||
}
|
||||
#if macro
|
||||
static public function deprecate<A>(at:haxe.PosInfos, useInstead:String, ret:A, ?p:haxe.PosInfos) {
|
||||
try {
|
||||
var lines = sys.io.File.getContent(at.fileName).split('\n'),
|
||||
min = 0,
|
||||
line = lines[at.lineNumber - 1];
|
||||
|
||||
for (i in 0...at.lineNumber-1)
|
||||
min += lines[i].length + 1;
|
||||
|
||||
var max = min + line.length;
|
||||
|
||||
function count(haystack:String, needle)
|
||||
return haystack.split(needle).length - 1;
|
||||
|
||||
if (count(line, p.methodName) == 1) {
|
||||
min += line.indexOf(p.methodName);
|
||||
max = min + p.methodName.length;
|
||||
}
|
||||
Context.warning(p.className + '::' + p.methodName + ' is deprecated. Use $useInstead instead', Context.makePosition( {
|
||||
min: min,
|
||||
max: max,
|
||||
file: at.fileName
|
||||
}));
|
||||
}
|
||||
catch (e:Dynamic)
|
||||
haxe.Log.trace('This function is deprecated, use $useInstead instead. Call site: ${p.className}@${p.lineNumber}');
|
||||
|
||||
return ret;
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -15,22 +15,24 @@ using tink.core.Outcome;
|
||||
class Types {
|
||||
static var types = new Map<Int,Void->Type>();
|
||||
static var idCounter = 0;
|
||||
macro static public function getType(id:Int):Type {
|
||||
|
||||
macro static public function getType(id:Int):Type
|
||||
return types.get(id)();
|
||||
}
|
||||
static public function getID(t:Type, ?reduced = true) {
|
||||
if (reduced)
|
||||
t = reduce(t);
|
||||
return
|
||||
switch (t) {
|
||||
case TAbstract(t, _): t.toString();
|
||||
case TInst(t, _): t.toString();
|
||||
case TEnum(t, _): t.toString();
|
||||
case TType(t, _): t.toString();
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
static public function accessToName(v:VarAccess, ?read = true) {
|
||||
|
||||
static public function getID(t:Type, ?reduced = true)
|
||||
return
|
||||
if (reduced)
|
||||
getID(reduce(t), false);
|
||||
else
|
||||
switch (t) {
|
||||
case TAbstract(t, _): t.toString();
|
||||
case TInst(t, _): t.toString();
|
||||
case TEnum(t, _): t.toString();
|
||||
case TType(t, _): t.toString();
|
||||
default: null;
|
||||
}
|
||||
|
||||
static public function accessToName(v:VarAccess, ?read = true)
|
||||
return
|
||||
switch (v) {
|
||||
case AccNormal, AccInline: 'default';
|
||||
@@ -40,7 +42,7 @@ class Types {
|
||||
default:
|
||||
throw 'not implemented';
|
||||
}
|
||||
}
|
||||
|
||||
static function getDeclaredFields(t:ClassType, out:Array<ClassField>, marker:Map<String,Bool>) {
|
||||
for (field in t.fields.get())
|
||||
if (!marker.exists(field.name)) {
|
||||
@@ -50,9 +52,8 @@ class Types {
|
||||
if (t.isInterface)
|
||||
for (t in t.interfaces)
|
||||
getDeclaredFields(t.t.get(), out, marker);
|
||||
else
|
||||
if (t.superClass != null)
|
||||
getDeclaredFields(t.superClass.t.get(), out, marker);
|
||||
else if (t.superClass != null)
|
||||
getDeclaredFields(t.superClass.t.get(), out, marker);
|
||||
}
|
||||
|
||||
static var fieldsCache = new Map();
|
||||
@@ -80,7 +81,7 @@ class Types {
|
||||
switch (member.typeof()) {
|
||||
case Success(t): t;
|
||||
case Failure(f):
|
||||
switch (reduce(field.type)) {
|
||||
switch reduce(field.type) {
|
||||
case TFun(args, _):
|
||||
var fArgs = [],
|
||||
fParams = [];
|
||||
@@ -144,23 +145,23 @@ class Types {
|
||||
|
||||
static public function isSubTypeOf(t:Type, of:Type, ?pos)
|
||||
return
|
||||
ECheckType(ECheckType('null'.resolve(), toComplex(t)).at(pos), toComplex(of)).at(pos).typeof();
|
||||
ECheckType(ECheckType(macro null, toComplex(t)).at(pos), toComplex(of)).at(pos).typeof();
|
||||
|
||||
static public function isDynamic(t:Type)
|
||||
return switch(reduce(t)) {
|
||||
return switch reduce(t) {
|
||||
case TDynamic(_): true;
|
||||
default: false;
|
||||
}
|
||||
|
||||
static public function toType(t:ComplexType, ?pos)
|
||||
return [
|
||||
'_'.define(t, pos),
|
||||
'_'.resolve(pos)
|
||||
].toBlock(pos).typeof();
|
||||
static public function toType(t:ComplexType, ?pos:Position)
|
||||
return (macro @:pos(pos.sanitize()) {
|
||||
var v:$t = null;
|
||||
v;
|
||||
}).typeof();
|
||||
|
||||
static public inline function instantiate(t:TypePath, ?args, ?pos) {
|
||||
static public inline function instantiate(t:TypePath, ?args, ?pos)
|
||||
return ENew(t, args == null ? [] : args).at(pos);
|
||||
}
|
||||
|
||||
static public function asTypePath(s:String, ?params):TypePath {
|
||||
var parts = s.split('.');
|
||||
var name = parts.pop(),
|
||||
@@ -177,39 +178,38 @@ class Types {
|
||||
sub: sub
|
||||
};
|
||||
}
|
||||
|
||||
static public inline function asComplexType(s:String, ?params)
|
||||
return TPath(asTypePath(s, params));
|
||||
|
||||
static public inline function reduce(type:Type, ?once)
|
||||
return Context.follow(type, once);
|
||||
|
||||
static public function isVar(field:ClassField) {
|
||||
static public function isVar(field:ClassField)
|
||||
return switch (field.kind) {
|
||||
case FVar(_, _): true;
|
||||
default: false;
|
||||
}
|
||||
}
|
||||
|
||||
static public function register(type:Void->Type):Int {
|
||||
var id = idCounter++;
|
||||
types.set(id, type);
|
||||
return id;
|
||||
}
|
||||
static function paramsToComplex(params:Array<Type>):Array<TypeParam> {
|
||||
var ret = [];
|
||||
for (p in params)
|
||||
ret.push(TPType(toComplex(p, true)));
|
||||
return ret;
|
||||
types.set(idCounter, type);
|
||||
return idCounter++;
|
||||
}
|
||||
|
||||
static function paramsToComplex(params:Array<Type>):Array<TypeParam>
|
||||
return [for (p in params) TPType(toComplex(p))];
|
||||
|
||||
static function baseToComplex(t:BaseType, params:Array<Type>)
|
||||
return asComplexType(t.module + '.' + t.name, paramsToComplex(params));
|
||||
|
||||
static public function toComplex(type:Type, ?pretty = false):ComplexType {
|
||||
static public function toComplex(type:Type):ComplexType {
|
||||
var ret = haxe.macro.TypeTools.toComplexType(type);
|
||||
if (ret == null)
|
||||
ret = lazyComplex(function () return type);
|
||||
return ret;
|
||||
}
|
||||
static public function lazyComplex(f:Void->Type) {
|
||||
|
||||
static public function lazyComplex(f:Void->Type)
|
||||
return
|
||||
TPath({
|
||||
pack : ['haxe','macro'],
|
||||
@@ -217,5 +217,4 @@ class Types {
|
||||
params : [TPExpr('tink.macro.Types.getType'.resolve().call([register(f).toExpr()]))],
|
||||
sub : null,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user