Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
df01d82300 | ||
![]() |
9b4e9cb81f | ||
![]() |
b90aae8386 | ||
![]() |
ab34b31bbd | ||
![]() |
ad3526795c | ||
![]() |
f4bf23a66b | ||
![]() |
a01a1b16ae | ||
![]() |
1a404103ca | ||
![]() |
b4bfa69376 | ||
![]() |
b17005d9ab | ||
![]() |
61505ec63b | ||
![]() |
ef2054d8ff | ||
![]() |
0683be706c | ||
![]() |
78e9087ba2 | ||
![]() |
6b8aefa7ca | ||
![]() |
0db8ee09f1 | ||
![]() |
dc29f07217 | ||
![]() |
b02e27b589 | ||
![]() |
30c4196f4f |
@@ -335,7 +335,7 @@ The first thing to point out is that constructors are handled separately. This i
|
||||
|
||||
As for the rest of the members, you can just iterate over them. It's worth noting that the iterator runs over a snapshot made at the time of its creation, so removing and adding fields during iteration has no effect on the iteration itself.
|
||||
|
||||
You can add a member. If you try adding a member named `"new"`, you'll get an exception. So don't do it. Read up on constructors below. If you try adding a duplicate member, you will get a compilation error at the second member's `Position`. If you add a member that already exists in the super class, the `override` is added automatically.
|
||||
You can add a member. If you try adding a member named `"new"`, you'll get an exception - so don't. Find out about how tink_macro handles constructors below. If you add a member that already exists in the super class, the `override` is added automatically.
|
||||
|
||||
And when you're done, you can `export` everything to an array of fields. If you set `verbose` to true, you will get compiler warnings for every generated field at the position of the field. This is way you can see the generated code even if the application cannot compile for some reason.
|
||||
|
||||
@@ -343,7 +343,7 @@ The intended use is with `run` that will send the same `ClassBuilder` through a
|
||||
|
||||
## Constructor
|
||||
|
||||
Constructors are relatively tricky, especially when you have inheritance. If you do not specify a constructor, than that of the the super class is used. If you do specify one, then it needn't be compatible with the super class, but it needs to call it. Macros represent them as an instance field called `new` that must be a function. However if you think about it, a constructor belongs to a class, not an instance. So this is all a little dodgy.
|
||||
Constructors are relatively tricky, especially when you have inheritance. If you do not specify a constructor, than that of the the super class is used. If you do specify one, then it needn't be compatible with the super class, but it needs to call it. Macros represent them as an instance field called `new` that must be a function. However if you think about it, a constructor belongs to a class, not an instance. So this is all a little dodgy. The constructor API is an attempt to create a more rigid solution.
|
||||
|
||||
The `Constructor` API is the result of countless struggles with constructors. Still it may not be for you. In that case feedback is appreciated and currently the suggested method is to deal with the constructor after you've exported all fields from the `ClassBuilder`.
|
||||
|
||||
|
21
haxelib.json
21
haxelib.json
@@ -1 +1,20 @@
|
||||
{"name":"tink_macro","license":"MIT","tags":["tink","macro","utility"],"classPath":"src","description":"The macro toolkit ;)","contributors":["back2dos"],"releasenote":"Extended API.","version":"0.5.0","url":"http://haxetink.org/tink_macro","dependencies":{"tink_core":""}}
|
||||
{
|
||||
"name": "tink_macro",
|
||||
"license": "MIT",
|
||||
"tags": [
|
||||
"tink",
|
||||
"macro",
|
||||
"utility"
|
||||
],
|
||||
"classPath": "src",
|
||||
"description": "The macro toolkit ;)",
|
||||
"contributors": [
|
||||
"back2dos"
|
||||
],
|
||||
"releasenote": "Minor simplification in constructor generation.",
|
||||
"version": "0.6.4",
|
||||
"url": "http://haxetink.org/tink_macro",
|
||||
"dependencies": {
|
||||
"tink_core": ""
|
||||
}
|
||||
}
|
@@ -17,7 +17,7 @@ typedef Unops = tink.macro.Ops.Unary;
|
||||
|
||||
//TODO: consider adding stuff from haxe.macro.Expr here
|
||||
typedef MacroOutcome<D, F> = tink.core.Outcome<D, F>;
|
||||
typedef MacroOutcomeTools = tink.core.Outcome.OutcomeTools;
|
||||
typedef MacroOutcomeTools = tink.OutcomeTools;
|
||||
|
||||
typedef Option<T> = haxe.ds.Option<T>;
|
||||
|
||||
@@ -36,59 +36,5 @@ class MacroApi {
|
||||
|
||||
static public function pos()
|
||||
return haxe.macro.Context.currentPos();
|
||||
|
||||
static public var typeNotFound(get, null):Signal<TypeResolution>;
|
||||
|
||||
static function get_typeNotFound() {
|
||||
if (typeNotFound == null) {
|
||||
var trigger = Signal.trigger();
|
||||
|
||||
var listening = false;
|
||||
|
||||
function register() {
|
||||
if (listening) return;
|
||||
listening = true;
|
||||
|
||||
haxe.macro.Context.onTypeNotFound(function (name:String) {
|
||||
@:privateAccess Positions.errorFunc = @:privateAccess Positions.abortTypeBuild;
|
||||
|
||||
var def = Ref.to(Left(name));
|
||||
|
||||
try trigger.trigger(def)
|
||||
catch (abort:tink.macro.Positions.AbortBuild) {
|
||||
var cl = macro class {
|
||||
static var __error = ${Positions.errorExpr(abort.pos, abort.message)};
|
||||
}
|
||||
var path = name.split('.');
|
||||
cl.name = path.pop();
|
||||
cl.pack = path;
|
||||
cl.pos = abort.pos;
|
||||
def.value = Right(cl);
|
||||
}
|
||||
|
||||
@:privateAccess Positions.errorFunc = @:privateAccess Positions.contextError;
|
||||
|
||||
return switch def.value {
|
||||
case Right(def): def;
|
||||
default: null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
register();
|
||||
|
||||
haxe.macro.Context.onMacroContextReused(function () {
|
||||
listening = false;
|
||||
return true;
|
||||
});
|
||||
|
||||
var ret = trigger.asSignal();
|
||||
typeNotFound = new Signal(function (cb) {
|
||||
register();
|
||||
return ret.handle(cb);
|
||||
});
|
||||
}
|
||||
return typeNotFound;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -10,41 +10,49 @@ using Lambda;
|
||||
|
||||
class ClassBuilder {
|
||||
|
||||
var memberMap:Map<String,Member>;
|
||||
var memberList:Array<Member>;
|
||||
var macros:Map<String,Field>;
|
||||
var constructor:Null<Constructor>;
|
||||
public var target(default, null):ClassType;//TODO: this could be lazy
|
||||
public var target(default, null):ClassType;
|
||||
var superFields:Map<String,Bool>;
|
||||
var keepers:Array<Expr>;//hack to force field generation
|
||||
public function new() {
|
||||
this.memberMap = new Map();
|
||||
|
||||
var initializeFrom:Array<Field>;
|
||||
|
||||
public function new(?target, ?fields) {
|
||||
if (target == null)
|
||||
target = Context.getLocalClass().get();
|
||||
|
||||
if (fields == null)
|
||||
fields = Context.getBuildFields();
|
||||
|
||||
this.initializeFrom = fields;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (initializeFrom == null) return;
|
||||
|
||||
var fields = initializeFrom;
|
||||
initializeFrom = null;
|
||||
|
||||
this.memberList = [];
|
||||
this.macros = new Map();
|
||||
this.target = Context.getLocalClass().get();
|
||||
|
||||
switch (target.kind) {
|
||||
case KAbstractImpl(a):
|
||||
//TODO: remove this whole workaround
|
||||
var meta = target.meta;
|
||||
for (tag in a.get().meta.get())
|
||||
if (!meta.has(tag.name))
|
||||
meta.add(tag.name, tag.params, tag.pos);
|
||||
default:
|
||||
}
|
||||
|
||||
for (field in Context.getBuildFields())
|
||||
for (field in fields)
|
||||
if (field.access.has(AMacro))
|
||||
macros.set(field.name, field)
|
||||
else if (field.name == 'new') {
|
||||
var m:Member = field;
|
||||
this.constructor = new Constructor(this, m.getFunction().sure(), m.isPublic, m.pos);
|
||||
this.constructor = new Constructor(this, m.getFunction().sure(), m.isPublic, m.pos, field.meta);
|
||||
}
|
||||
else
|
||||
addMember(field);
|
||||
else
|
||||
doAddMember(field);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function getConstructor(?fallback:Function):Constructor {
|
||||
init();
|
||||
if (constructor == null)
|
||||
if (fallback != null)
|
||||
new Constructor(this, fallback);
|
||||
@@ -81,10 +89,13 @@ class ClassBuilder {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public function hasConstructor():Bool
|
||||
public function hasConstructor():Bool {
|
||||
init();
|
||||
return this.constructor != null;
|
||||
}
|
||||
|
||||
public function export(?verbose):Array<Field> {
|
||||
if (initializeFrom != null) return null;
|
||||
var ret = (constructor == null || target.isInterface) ? [] : [constructor.toHaxe()];
|
||||
for (member in memberList) {
|
||||
if (member.isBound)
|
||||
@@ -104,12 +115,16 @@ class ClassBuilder {
|
||||
|
||||
return ret;
|
||||
}
|
||||
public function iterator():Iterator<Member>
|
||||
public function iterator():Iterator<Member> {
|
||||
init();
|
||||
return this.memberList.copy().iterator();
|
||||
}
|
||||
|
||||
public function hasOwnMember(name:String):Bool
|
||||
public function hasOwnMember(name:String):Bool {
|
||||
init();
|
||||
return
|
||||
macros.exists(name) || memberMap.exists(name);
|
||||
macros.exists(name) || memberByName(name).isSuccess();
|
||||
}
|
||||
|
||||
public function hasSuperField(name:String):Bool {
|
||||
if (superFields == null) {
|
||||
@@ -124,38 +139,48 @@ class ClassBuilder {
|
||||
}
|
||||
return superFields.get(name);
|
||||
}
|
||||
public function memberByName(name:String, ?pos:Position)
|
||||
return
|
||||
if (memberMap.exists(name)) Success(memberMap.get(name));
|
||||
else pos.makeFailure('unknown member $name');
|
||||
|
||||
public function removeMember(member:Member):Bool
|
||||
|
||||
public function memberByName(name:String, ?pos:Position) {
|
||||
init();
|
||||
for (m in memberList)
|
||||
if (m.name == name)
|
||||
return Success(m);
|
||||
|
||||
return pos.makeFailure('unknown member $name');
|
||||
}
|
||||
|
||||
public function removeMember(member:Member):Bool {
|
||||
init();
|
||||
return
|
||||
member != null
|
||||
&&
|
||||
memberMap.get(member.name) == member
|
||||
&&
|
||||
memberMap.remove(member.name)
|
||||
&&
|
||||
memberList.remove(member);
|
||||
}
|
||||
|
||||
public function hasMember(name:String):Bool
|
||||
return hasOwnMember(name) || hasSuperField(name);
|
||||
|
||||
public function addMember(m:Member, ?front:Bool = false):Member {
|
||||
|
||||
function doAddMember(m:Member, ?front:Bool = false):Member {
|
||||
init();
|
||||
|
||||
if (m.name == 'new')
|
||||
throw 'Constructor must not be registered as ordinary member';
|
||||
|
||||
if (hasOwnMember(m.name))
|
||||
m.pos.error('duplicate member declaration ' + m.name);
|
||||
if (!m.isStatic && hasSuperField(m.name))
|
||||
m.overrides = true;
|
||||
memberMap.set(m.name, m);
|
||||
//if (hasOwnMember(m.name))
|
||||
//m.pos.error('duplicate member declaration ' + m.name);
|
||||
|
||||
if (front)
|
||||
memberList.unshift(m);
|
||||
else
|
||||
memberList.push(m);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public function addMember(m:Member, ?front:Bool = false):Member {
|
||||
doAddMember(m, front);
|
||||
|
||||
if (!m.isStatic && hasSuperField(m.name))
|
||||
m.overrides = true;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ class Constructor {
|
||||
var onGenerateHooks:Array<Function->Void>;
|
||||
var superCall:Expr;
|
||||
var owner:ClassBuilder;
|
||||
var keepers:Array<Expr>;//hack to force field generation
|
||||
var meta:Metadata;
|
||||
public var isPublic:Null<Bool>;
|
||||
|
||||
public function new(owner:ClassBuilder, f:Function, ?isPublic:Null<Bool> = null, ?pos:Position, ?meta:Metadata) {
|
||||
@@ -34,7 +34,7 @@ class Constructor {
|
||||
this.args = [];
|
||||
this.beforeArgs = [];
|
||||
this.afterArgs = [];
|
||||
this.keepers = [];
|
||||
this.meta = meta;
|
||||
|
||||
this.oldStatements =
|
||||
if (f == null) [];
|
||||
@@ -96,14 +96,7 @@ class Constructor {
|
||||
case Success(member): member.addMeta(':isVar');
|
||||
default:
|
||||
}
|
||||
|
||||
if (Context.defined('dce') && Context.definedValue('dce') == 'full') {
|
||||
if (keepers.length == 0)
|
||||
keepers.push(macro return);
|
||||
keepers.push(macro this.$name = $e);
|
||||
}
|
||||
addStatement(macro @:pos(pos) if (false) { var $tmp = this.$name; $i{tmp} = $e; }, true);
|
||||
addStatement(macro @:pos(pos) (cast this).$name = $e, options.prepend);
|
||||
addStatement(macro @:pos(pos) (cast this).$name = if (true) $e else this.$name, options.prepend);
|
||||
}
|
||||
else
|
||||
addStatement(macro @:pos(pos) this.$name = $e, options.prepend);
|
||||
@@ -116,7 +109,6 @@ class Constructor {
|
||||
return [superCall]
|
||||
.concat(nuStatements)
|
||||
.concat(oldStatements)
|
||||
.concat(keepers)
|
||||
.toBlock(pos);
|
||||
|
||||
public function onGenerate(hook)
|
||||
@@ -137,7 +129,7 @@ class Constructor {
|
||||
access : isPublic ? [APublic] : [],
|
||||
kind : FFun(f),
|
||||
pos : pos,
|
||||
meta : []
|
||||
meta : this.meta,
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@ using StringTools;
|
||||
using tink.macro.Positions;
|
||||
using tink.macro.Exprs;
|
||||
using tink.macro.Types;
|
||||
using tink.core.Outcome;
|
||||
using tink.CoreApi;
|
||||
|
||||
typedef VarDecl = { name : String, type : ComplexType, expr : Null<Expr> };
|
||||
typedef ParamSubst = {
|
||||
@@ -180,6 +180,11 @@ class Exprs {
|
||||
static public function yield(e:Expr, yielder:Expr->Expr, ?options: { ?leaveLoops: Bool }):Expr {
|
||||
inline function rec(e)
|
||||
return yield(e, yielder, options);
|
||||
|
||||
if (options == null)
|
||||
options = { };
|
||||
|
||||
var loops = options.leaveLoops != true;
|
||||
return
|
||||
if (e == null || e.expr == null) e;
|
||||
else switch (e.expr) {
|
||||
@@ -197,9 +202,9 @@ class Exprs {
|
||||
for (c in cases)
|
||||
c.expr = rec(c.expr);
|
||||
ESwitch(e, cases, rec(edef)).at(e.pos);
|
||||
case EFor(it, expr) if (options == null || options.leaveLoops != true):
|
||||
case EFor(it, expr) if (loops):
|
||||
EFor(it, rec(expr)).at(e.pos);
|
||||
case EWhile(cond, body, normal) if (options == null || options.leaveLoops != true):
|
||||
case EWhile(cond, body, normal) if (loops):
|
||||
EWhile(cond, rec(body), normal).at(e.pos);
|
||||
case EBreak, EContinue: e;
|
||||
case EBinop(OpArrow, value, jump) if (jump.expr == EContinue || jump.expr == EBreak):
|
||||
@@ -234,149 +239,7 @@ 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;
|
||||
|
||||
var ret = switch(mappedSource.expr) {
|
||||
case ECheckType(e, t): ECheckType(rec(e), t);
|
||||
case ECast(e, t): ECast(rec(e), t);
|
||||
case EArray(e1, e2): EArray(rec(e1), rec(e2));
|
||||
case EField(e, field): EField(rec(e), field);
|
||||
case EParenthesis(e): EParenthesis(rec(e));
|
||||
case ECall(e, params): ECall(rec(e), typedMapArray(params, f, ctx, pos));
|
||||
case EIf(econd, eif, eelse): EIf(rec(econd), rec(eif), rec(eelse));
|
||||
case ETernary(econd, eif, eelse): ETernary(rec(econd), rec(eif), rec(eelse));
|
||||
case EBlock(exprs): EBlock(exprs.typedMapArray(f, ctx.copy(), pos));
|
||||
case EArrayDecl(exprs): EArrayDecl(exprs.typedMapArray(f, ctx, pos));
|
||||
case EIn(e1, e2): EIn(rec(e1), rec(e2));
|
||||
case EWhile(econd, e, normalWhile): EWhile(rec(econd), rec(e), normalWhile);
|
||||
case EUntyped(e): EUntyped(rec(e));
|
||||
case EThrow(e): EThrow(rec(e));
|
||||
case EReturn(e): EReturn(rec(e));
|
||||
case EDisplay(e, t): EDisplay(rec(e), t);
|
||||
case EDisplayNew(t): EDisplayNew(t);
|
||||
case EUnop(op, postFix, e): EUnop(op, postFix, rec(e));
|
||||
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):
|
||||
EObjectDecl([for (field in fields) {
|
||||
field: field.field,
|
||||
expr: rec(field.expr)
|
||||
}]);
|
||||
case ESwitch(expr, cases, def):
|
||||
var newCases = cases;
|
||||
newCases = [];
|
||||
expr = rec(expr);
|
||||
switch (expr.typeof(ctx).sure().reduce()) {
|
||||
case TEnum(e, _):
|
||||
var enumDef = e.get();
|
||||
for (c in cases) {
|
||||
var caseValues = [],
|
||||
innerCtx = ctx.copy();
|
||||
for (v in c.values) {
|
||||
var newVal = v;
|
||||
switch (v.expr) {
|
||||
case ECall(e, params):
|
||||
switch (e.getIdent()) {
|
||||
case Success(s):
|
||||
if (!enumDef.constructs.exists(s))
|
||||
e.reject('Constructor is not a part of ' + enumDef.name);
|
||||
newVal = enumDef.module.split('.').concat([enumDef.name, s]).drill(e.pos);
|
||||
if (caseValues.length == 0) {
|
||||
switch (newVal.typeof(ctx).sure().reduce()) {
|
||||
case TFun(args, _):
|
||||
for (arg in 0...args.length) {
|
||||
innerCtx.push({
|
||||
name:params[arg].getName().sure(),
|
||||
type: args[arg].t.toComplex(),
|
||||
expr: null
|
||||
});
|
||||
}
|
||||
default:
|
||||
e.reject('Constructor may not have arguments');
|
||||
}
|
||||
}
|
||||
newVal = newVal.call(params, v.pos);
|
||||
default:
|
||||
e.reject();
|
||||
}
|
||||
default:
|
||||
v.reject();
|
||||
}
|
||||
caseValues.push(rec(newVal));
|
||||
}
|
||||
newCases.push( { expr: rec(c.expr, innerCtx), values: caseValues } );
|
||||
}
|
||||
case _:
|
||||
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):
|
||||
switch(it.expr) {
|
||||
case EIn(itIdent, itExpr):
|
||||
var innerCtx = ctx.copy();
|
||||
switch(itExpr.typeof(ctx)) {
|
||||
case Success(t):
|
||||
if (t.getID() == "IntIter")
|
||||
innerCtx.push( { name:itIdent.getIdent().sure(), type: "Int".asComplexType(), expr:null } );
|
||||
else
|
||||
innerCtx.push( { name:itIdent.getIdent().sure(), type: null, expr:itExpr.field("iterator").call().field("next").call() } );
|
||||
EFor(it, rec(expr, innerCtx));
|
||||
default:
|
||||
innerCtx.push( { name:itIdent.getIdent().sure(), type: null, expr:itExpr.field("iterator").call().field("next").call() } );
|
||||
EFor(it, rec(expr, innerCtx));
|
||||
}
|
||||
default:
|
||||
Context.error("Internal error in " + mappedSource.toString(), mappedSource.pos);
|
||||
}
|
||||
case ETry(e, catches):
|
||||
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):
|
||||
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) {
|
||||
var vExpr = v.expr == null ? null : typedMap(v.expr, f, ctx);
|
||||
if (v.type == null && vExpr != null)
|
||||
v.type = vExpr.typeof(ctx).sure().toComplex();
|
||||
ctx.push({ name:v.name, expr:null, type:v.type });
|
||||
ret.push({ name:v.name, expr:vExpr == null ? null : vExpr, type:v.type });
|
||||
}
|
||||
EVars(ret);
|
||||
default:
|
||||
mappedSource.expr;
|
||||
}
|
||||
return ret.at(pos == null ? source.pos : pos);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -436,10 +299,7 @@ class Exprs {
|
||||
return EBlock(exprs).at(pos);
|
||||
|
||||
static public inline function toBlock(exprs:Iterable<Expr>, ?pos)
|
||||
return toMBlock(Lambda.array(exprs), pos);
|
||||
|
||||
static inline function isUC(s:String)
|
||||
return StringTools.fastCodeAt(s, 0) < 0x5B;
|
||||
return toMBlock(Lambda.array(exprs), pos);
|
||||
|
||||
static public function drill(parts:Array<String>, ?pos:Position, ?target:Expr) {
|
||||
if (target == null)
|
||||
|
@@ -10,7 +10,7 @@ import haxe.macro.Type;
|
||||
using tink.macro.Exprs;
|
||||
using tink.macro.Positions;
|
||||
using tink.macro.Functions;
|
||||
using tink.core.Outcome;
|
||||
using tink.CoreApi;
|
||||
|
||||
class Types {
|
||||
static var types = new Map<Int,Void->Type>();
|
||||
|
Reference in New Issue
Block a user