Exact type to string conversion.

This commit is contained in:
Juraj Kirchheim
2021-03-14 12:58:10 +01:00
parent a383f7692b
commit 99a1fc3fa6
6 changed files with 106 additions and 2 deletions

View File

@@ -2,6 +2,8 @@ package tink.macro;
import haxe.macro.Expr; import haxe.macro.Expr;
import haxe.macro.Type; import haxe.macro.Type;
using haxe.macro.Tools;
using tink.MacroApi;
class Sisyphus { class Sisyphus {
@@ -61,8 +63,7 @@ class Sisyphus {
} }
} }
static public function toComplexType(type : Null<Type>) : Null<ComplexType> return {
public static function toComplexType(type : Null<Type>) : Null<ComplexType> return {
inline function direct() inline function direct()
return Types.toComplex(type, { direct: true }); return Types.toComplex(type, { direct: true });
switch (type) { switch (type) {
@@ -136,4 +137,61 @@ class Sisyphus {
}], }],
} }
} }
static function exactBase<T:BaseType>(r:haxe.macro.Type.Ref<T>, params:Array<Type>) {
var t = r.get();
var isMain = !t.isPrivate && switch t.pack {
case []: t.module == t.name || t.module == 'StdTypes';
default: StringTools.endsWith(t.module, '.${t.name}');
}
return (
if (isMain) t.pack.concat([t.name]).join('.')
else t.module + '.' + t.name
) + switch params {
case []: '';
case params:
'<${params.map(toExactString).join(', ')}>';
}
}
static function exactAnonField(c:ClassField) {
var kw =
switch c.kind {
case FMethod(_): 'function';
case FVar(_):
if (c.isFinal) 'final' else 'var';
}
return [for (m in c.meta.get()) m.toString() + ' '].join('') + '$kw ${c.name}' + (switch c.kind {
case FVar(read, write):
(
if (c.isFinal || (read == AccNormal && write == AccNormal)) ''
else '(${read.accessToName()}, ${read.accessToName(false)})'
) + ':' + c.type.toExactString();
case FMethod(_):
switch haxe.macro.Context.follow(c.type) {
case TFun(arg, ret): exactSig(arg, ret, ':');
default: throw 'assert';
}
}) + ';';
}
static function exactSig(args:Array<{name:String, opt:Bool, t:Type}>, ret:Type, sep:String)
return '(${[for (a in args) (if (a.opt) '?' else '') + a.name + ':' + toExactString(a.t)].join(', ')})$sep${toExactString(ret)}';
static public function toExactString(t:Type)
return switch t {
case TMono(t): t.toString();
case TEnum(r, params): exactBase(r, params);
case TInst(r, params): exactBase(r, params);
case TType(r, params): exactBase(r, params);
case TAbstract(r, params): exactBase(r, params);
case TFun(args, ret): exactSig(args, ret, '->');
case TAnonymous(a): '{ ${[for (f in a.get().fields) exactAnonField(f)].join(' ')} }';
case TDynamic(null): 'Dynamic';
case TDynamic(t): 'Dynamic<${toExactString(t)}>';
case TLazy(f): toExactString(f());
}
} }

View File

@@ -221,6 +221,10 @@ class Types {
} }
} }
/// like haxe.macro.TypeTools.toString, but not lossy
static public function toExactString(t:Type)
return Sisyphus.toExactString(t);
static public function toString(t:ComplexType) static public function toString(t:ComplexType)
return new Printer().printComplexType(t); return new Printer().printComplexType(t);

8
tests/Dummy.hx Normal file
View File

@@ -0,0 +1,8 @@
class Dummy {
public function new() {}
static public var p(default, never) = new Private();
}
private class Private {
public function new() {}
}

20
tests/ExactStrings.hx Normal file
View File

@@ -0,0 +1,20 @@
import haxe.macro.Context;
import haxe.macro.Context.typeof;
using tink.MacroApi;
class ExactStrings extends Base {
function test() {
function expect(s:String, e, ?pos)
assertEquals(s, typeof(e).toExactString(), pos);
expect('Dummy', macro new Dummy());
expect('nested.Dummy', macro new nested.Dummy());
expect('Dummy.Private', macro Dummy.p);
expect('nested.Dummy.Private', macro nested.Dummy.p);
expect('{ @foo var x:Int; }', macro (null:{@foo var x:Int;}));
expect('{ @bar var x:Int; }', macro (null:{@bar var x:Int;}));
expect('{ var x:Int; var y:Int; }', macro (null:{x:Int,y:Int}));
expect('{ var x:Int; var y:Int; }', macro (null:{y:Int,x:Int}));
expect('{ function foo(x:Int, ?y:Int):Void; }', macro (null:{ function foo(x:Int, ?y:Int):Void; }));
}
}

View File

@@ -1,6 +1,9 @@
package ; package ;
import haxe.unit.*; import haxe.unit.*;
#if macro
using haxe.macro.Tools;
#end
class Run { class Run {
#if !macro #if !macro
@@ -14,6 +17,7 @@ class Run {
new TypeMapTest(), new TypeMapTest(),
new Functions(), new Functions(),
new Misc(), new Misc(),
new ExactStrings(),
]; ];
#end #end
macro static function test() { macro static function test() {

10
tests/nested/Dummy.hx Normal file
View File

@@ -0,0 +1,10 @@
package nested;
class Dummy {
public function new() {}
static public var p(default, never) = new Private();
}
private class Private {
public function new() {}
}