ソースを参照

Add test for @:enum (#11155)

* Add test for enum abstract value extraction

* Add missing package
Rudy Ges 2 年 前
コミット
24015570d9
2 ファイル変更51 行追加0 行削除
  1. 40 0
      tests/unit/src/unit/AbstractEnumTools.hx
  2. 11 0
      tests/unit/src/unit/TestMisc.hx

+ 40 - 0
tests/unit/src/unit/AbstractEnumTools.hx

@@ -0,0 +1,40 @@
+// From https://code.haxe.org/category/macros/enum-abstract-values.html
+package unit;
+
+#if macro
+import haxe.macro.Context;
+import haxe.macro.Expr;
+using haxe.macro.Tools;
+#end
+
+class AbstractEnumTools {
+  public static macro function getValues(typePath:Expr):Expr {
+    // Get the type from a given expression converted to string.
+    // This will work for identifiers and field access which is what we need,
+    // it will also consider local imports. If expression is not a valid type path or type is not found,
+    // compiler will give a error here.
+    var type = Context.getType(typePath.toString());
+
+    // Switch on the type and check if it's an abstract with @:enum metadata
+    switch (type.follow()) {
+      case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")):
+        // @:enum abstract values are actually static fields of the abstract implementation class,
+        // marked with @:enum and @:impl metadata. We generate an array of expressions that access those fields.
+        // Note that this is a bit of implementation detail, so it can change in future Haxe versions, but it's been
+        // stable so far.
+        var valueExprs = [];
+        for (field in ab.impl.get().statics.get()) {
+          if (field.meta.has(":enum") && field.meta.has(":impl")) {
+            var fieldName = field.name;
+            valueExprs.push(macro $typePath.$fieldName);
+          }
+        }
+        // Return collected expressions as an array declaration.
+        return macro $a{valueExprs};
+      default:
+        // The given type is not an abstract, or doesn't have @:enum metadata, show a nice error message.
+        throw new Error(type.toString() + " should be @:enum abstract", typePath.pos);
+    }
+  }
+}
+

+ 11 - 0
tests/unit/src/unit/TestMisc.hx

@@ -103,6 +103,12 @@ class SubConstrOpt3 extends BaseConstrOpt {
 	}
 }
 
+enum abstract MyEnumAbstract(Int) {
+	var A = 1;
+	var B = 2;
+	var C = 3;
+}
+
 class TestMisc extends Test {
 
 	static var unit = "testing package conflict";
@@ -604,4 +610,9 @@ class TestMisc extends Test {
 		eq("NPE", try nf1.s catch (e:Any) "NPE");
 		eq("NPE", try nf2.s catch (e:Any) "NPE");
 	}
+
+	function testAbstractEnumTools() {
+		var values = AbstractEnumTools.getValues(MyEnumAbstract);
+		eq(values.join(","), "1,2,3");
+	}
 }