Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Trying to create a macro to copy all the static field and apply type …

…param specialization.
  • Loading branch information...
commit e0c7b54cf6a76f2c697225e886dc268876830a7f 1 parent 6e2f839
Andy Li authored
Showing with 274 additions and 0 deletions.
  1. +168 −0 hxLINQ/macro/SpecializeStatics.hx
  2. +106 −0 test/TestSpecializeStatics.hx
168 hxLINQ/macro/SpecializeStatics.hx
View
@@ -0,0 +1,168 @@
+package hxLINQ.macro;
+
+#if macro
+import haxe.macro.*;
+import haxe.macro.Expr;
+using hxLINQ.LINQ;
+#end
+class SpecializeStatics {
+ static public function specializeTypeParamDeclArray(a:Array<TypeParamDecl>, typeMap:Hash<ComplexType>):Array<TypeParamDecl> {
+ var ret = [];
+ for (tpd in a) {
+ if (typeMap.exists(tpd.name)) continue;
+
+ ret.push({
+ name: tpd.name,
+ constraints: tpd.constraints == null ? null : tpd.constraints.linq().select(function(ct,_) return specializeComplexType(ct, typeMap)).items,
+ params: tpd.params == null ? null : specializeTypeParamDeclArray(tpd.params, typeMap)
+ });
+ }
+ return ret;
+ }
+
+ static public function toSpecializeTypeParamDeclArray(a:Array<{ name: String, t: Type }>, typeMap:Hash<ComplexType>):Array<TypeParamDecl> {
+ var ret = [];
+ for (nt in a) {
+ if (typeMap.exists(nt.name)) continue;
+
+ ret.push({
+ name: nt.name,
+ constraints: switch(nt.t){
+ case TInst(t, params):
+ switch(t.get().kind) {
+ case KTypeParameter(constraints):
+ constraints.linq().select(function(c,_) return Context.toComplexType(c)).items;
+ default: throw t.get().kind;
+ }
+ default: throw nt.t;
+ },
+ params: []
+ });
+ }
+ return ret;
+ }
+
+ static public function specializeComplexType(t:ComplexType, typeMap:Hash<ComplexType>):ComplexType {
+ //trace(t);
+ var r = t == null ? null : switch (t) {
+ case TPath(p):
+ if (typeMap.exists(p.name)) {
+ typeMap.get(p.name);
+ } else {
+ try {
+ Context.typeof(macro cast(null, $t)); //if it is a type param, it will throw
+ t;
+ } catch (e:Dynamic) {
+ TPath({
+ pack: [],
+ name: p.name,
+ params: p.params.linq().select(function(p,_) return switch(p){
+ case TPType(t):
+ TPType(specializeComplexType(t, typeMap));
+ case TPExpr(e):
+ p;
+ }).items,
+ sub: p.sub
+ });
+ }
+ }
+ case TFunction(args, ret):
+ TFunction(args.linq().select(function(a,_) return specializeComplexType(a, typeMap)).items, specializeComplexType(ret, typeMap));
+ case TAnonymous(fields):
+ TAnonymous(fields.linq().select(function(field,_) return {
+ name: field.name,
+ doc: field.doc,
+ access: field.access,
+ kind: switch (field.kind) {
+ case FVar(t, e):
+ FVar(specializeComplexType(t, typeMap), e);
+ case FFun(f):
+ FFun({
+ args: f.args.linq().select(function(a, _) return {
+ name: a.name,
+ opt: a.opt,
+ type: specializeComplexType(a.type, typeMap),
+ value: a.value
+ }).items,
+ ret: specializeComplexType(f.ret, typeMap),
+ expr: f.expr,
+ params: specializeTypeParamDeclArray(f.params, typeMap)
+ });
+ case FProp(get, set, t, e):
+ FProp(get, set, specializeComplexType(t, typeMap), e);
+ },
+ pos: field.pos,
+ meta: field.meta
+ }).items);
+ case TParent(t):
+ TParent(specializeComplexType(t, typeMap));
+ case TExtend(p, fields):
+ throw "not supported yet " + t;
+ case TOptional(t):
+ TOptional(specializeComplexType(t, typeMap));
+ }
+ //trace(r);
+ return r;
+ }
+
+ @:macro static public function build(cls:ExprOf<Class<Dynamic>>, map:ExprOf<Array<Dynamic>>):Array<Field> {
+ var fields = Context.getBuildFields();
+ var clsType = switch (Context.typeof(cls)) {
+ case TType(t,p): switch(Context.getType(t.toString().split("#").join(""))) {
+ case TInst(t,p): t.get();
+ default: throw t.toString();
+ }
+ default: throw Context.typeof(cls);
+ }
+
+ var mapExpect = "map should be an Array of cast expressions, eg. [cast(T,Int), cast(C,Array<Int>)]";
+ var typeMap = new Hash<ComplexType>();
+ switch (map.expr) {
+ case EArrayDecl(vs):
+ for (v in vs) {
+ switch (v.expr) {
+ case ECast(e,t):
+ var paramName = switch (e.expr) {
+ case EConst(c): switch (c) {
+ case CIdent(s): s;
+ default: throw mapExpect;
+ }
+ default: throw mapExpect;
+ }
+ typeMap.set(paramName, t);
+ default: throw mapExpect;
+ }
+ }
+ default: throw mapExpect;
+ }
+
+ for (staticMthd in clsType.statics.get()) {
+ var staticMthdFunc = switch(Context.getTypedExpr(staticMthd.expr()).expr) {
+ case EFunction(name, f): f;
+ default: throw Context.getTypedExpr(staticMthd.expr()).expr;
+ }
+ var field = {
+ name: staticMthd.name,
+ doc: staticMthd.doc,
+ access: staticMthd.isPublic ? [AStatic, APublic] : [AStatic, APrivate],
+ kind: FFun({
+ args: staticMthdFunc.args.linq().select(function(arg, _){
+ return {
+ name: arg.name,
+ opt: arg.opt,
+ type: specializeComplexType(arg.type, typeMap),
+ value: arg.value
+ }
+ }).items,
+ ret: specializeComplexType(staticMthdFunc.ret, typeMap),
+ expr: staticMthdFunc.expr,
+ params: toSpecializeTypeParamDeclArray(staticMthd.params, typeMap)
+ }),
+ pos: staticMthd.pos
+ }
+ trace(field);
+ fields.push(field);
+ }
+ return fields;
+ }
+}
106 test/TestSpecializeStatics.hx
View
@@ -0,0 +1,106 @@
+#if macro
+import haxe.macro.Context;
+import haxe.macro.Expr;
+#end
+
+class A {
+ static public function a<T>(_a:T):T {
+ return _a;
+ }
+}
+
+#if !macro
+@:build(hxLINQ.macro.SpecializeStatics.build(A, [cast(T,String)]))
+#end
+class A_String {
+
+}
+
+class B {
+ static public function b<T1,T2>(b1:T1, b2:T2):T1 {
+ return b1;
+ }
+}
+
+#if !macro
+@:build(hxLINQ.macro.SpecializeStatics.build(B, [cast(T1,String), cast(T2,Int)]))
+#end
+class B_StringInt {
+
+}
+
+#if !macro
+@:build(hxLINQ.macro.SpecializeStatics.build(B, [cast(T2,String)]))
+#end
+class B_String {
+
+}
+
+
+class C<C1,C2> {
+ public var c1:C1;
+ public var c2:C2;
+
+ public function new(c1:C1, c2:C2):Void {
+ this.c1 = c1;
+ this.c2 = c2;
+ }
+
+ static public function c<T, A:Iterable<T>>(_c:C<T,A>, clause:A->Array<T>):C<T,Array<T>> {
+ return null;//new C(_c.c1, clause(_c.c2));
+ }
+}
+
+#if !macro
+@:build(hxLINQ.macro.SpecializeStatics.build(C, [cast(A, Array<T>)]))
+#end
+class C_Array {
+
+}
+
+class TestSpecializeStatics extends haxe.unit.TestCase {
+ @:macro public static function typeOf(e:Expr):ExprOf<String> {
+ var type = Std.string(Context.typeof(e));
+ return Context.makeExpr(type, e.pos);
+ }
+
+ #if !macro
+ public function testAClassFields():Void {
+ var classFields = Type.getClassFields(A_String);
+ this.assertEquals(1, classFields.length);
+ this.assertEquals("a", classFields[0]);
+ this.assertEquals("TFun([{ name => _a, t => TInst(String,[]), opt => false }],TInst(String,[]))", typeOf(A_String.a));
+ }
+ public function testAInstanceFields():Void {
+ var classFields = Type.getInstanceFields(A_String);
+ this.assertEquals(0, classFields.length);
+ }
+
+ public function testBClassFields():Void {
+ var classFields = Type.getClassFields(B_StringInt);
+ this.assertEquals(1, classFields.length);
+ this.assertEquals("b", classFields[0]);
+ this.assertEquals("TFun([{ name => b1, t => TInst(String,[]), opt => false },{ name => b2, t => TAbstract(Int,[]), opt => false }],TInst(String,[]))", typeOf(B_StringInt.b));
+
+ var classFields = Type.getClassFields(B_String);
+ this.assertEquals(1, classFields.length);
+ this.assertEquals("b", classFields[0]);
+ this.assertEquals(1, B_String.b(1, "2"));
+ }
+ public function testBInstanceFields():Void {
+ var classFields = Type.getInstanceFields(B_StringInt);
+ this.assertEquals(0, classFields.length);
+ }
+
+ public function testC() {
+ C_Array.c(new C("a", []), function(l) return l);
+ this.assertTrue(true);
+ }
+
+ public static function main():Void {
+ var runner = new haxe.unit.TestRunner();
+ runner.add(new TestSpecializeStatics());
+ runner.run();
+ }
+ #end
+}
Please sign in to comment.
Something went wrong with that request. Please try again.