[Macro] Extends Abstract Enum

98 views
Skip to first unread message

Théo Sabattié

unread,
Sep 8, 2016, 6:07:25 PM9/8/16
to Haxe
Hi everyone ! :D

I am trying to copy field of an abstract to an other.

Instead of:

@:enum abstract PrimitiveNumber(String) to String 
{
    var FLOAT = "FLOAT";
    var INT   = "INT";
}

@:enum abstract PrimitiveType(String) to String
{
   
var FLOAT  = "FLOAT";
   
var INT    = "INT";
   
var STRING = "STRING";
   
var BOOL   = "BOOL";
}

@:enum abstract Type(String) to String
{
   
var FLOAT  = "FLOAT";
   
var INT    = "INT";

   
var STRING = "STRING";
   
var BOOL   = "BOOL";
   
var OBJECT = "OBJECT";
   
var LIST   = "LIST";
   
var MAP    = "MAP";
   
var ENUM   = "ENUM";
}

I would like get write that:

@:enum abstract PrimitiveNumber(String) to String 
{
    var FLOAT = "FLOAT";
    var INT   = "INT";
}

@:build(AbstractTools.extendEnum(PrimitiveNumber))
@:
enum abstract PrimitiveType(String) to String 
{
    
var STRING = "STRING";
    
var BOOL   = "BOOL";
}

@:build(AbstractTools.extendEnum(PrimitiveType))
@:
enum abstract Type(String) to String 
{
    
var OBJECT = "OBJECT";
    
var LIST   = "LIST";
    
var MAP    = "MAP";
    
var ENUM   = "ENUM";
}

I wrote that:

#if macro
import haxe.macro.Context;
import haxe.macro.Expr;
using haxe.macro.Tools;
#end


class AbstractTools {
   
public static macro function extendEnum(typePath:Expr):Array<Field> {
       
var fields = Context.getBuildFields();
       
var type   = Context.getType(typePath.toString());
       
var lField:Field;
       
       
switch (type.follow()) {
           
case TAbstract(_.get() => ab, _) if (ab.meta.has(":enum")):
               
var valueExprs = [];
               
               
for (classField in ab.impl.get().statics.get()) {
                   
if (classField.meta.has(":enum") && classField.meta.has(":impl")) {
                       
var fieldName = classField.name;
                       
                        lField
= {
                            name
: fieldName,
                            doc
: null,
                            meta
: [],
                            access
: [AStatic, APublic],
                            kind
: FVar(macro : String, macro $typePath.$fieldName),
                            pos
: Context.currentPos()
                       
};
                        fields
.push(lField);
                   
}
               
}
           
default:
               
throw new Error(type.toString() + " should be @:enum abstract", typePath.pos);
       
}
       
       
return fields;
   
}
}

But build meta seems to work only with string parameter because I get this error:
PrimitiveNumber should be string on compilation but I have autocompletion.

kind: FVar(macro : String, macro $typePath.$fieldName),

Here, "String" must be type of abstract, but I don't know how to get it.

Do you have an idea to fix that? :)

Thanks

Théo Sabattié.

Yoni Gueta

unread,
Sep 9, 2016, 5:54:40 AM9/9/16
to Haxe


you need to transform your  type to a complexType:


(look at compiler output tab)

Théo Sabattié

unread,
Sep 9, 2016, 8:06:25 AM9/9/16
to Haxe
Great! Thanks a lot for the fix ! 

There is a last issue :
trace(Typer.OBJECT);
trace(Typer.STRING);
trace(Typer.FLOAT);

There isn"t problem for first and second but the third break compilation with this error:
Test.hx:11: characters 10-21 : Typer has no field FLOAT

Is there a way to invoke build of PrimitiveType to get its built fields?

Thanks.

Yoni Gueta

unread,
Sep 10, 2016, 6:27:26 AM9/10/16
to Haxe


your welcome :)

it seems  that your'e skipping the fields due to this condition:   "if ((classField.meta.has(":enum") && classField.meta.has(":impl")) "
the PrimitiveNumber fields exist but are stripped from their meta when built by the Typer. im  not sure why.



Théo Sabattié

unread,
Sep 10, 2016, 2:37:20 PM9/10/16
to Haxe
Ok', but if I remove that condition I get an error.

We can extend PrimitiveNumber and PrimitiveType for Type like this:

@:enum abstract PrimitiveNumber(String) to String 
{
    var FLOAT = "FLOAT";
    var INT   = "INT";
}

@:build(AbstractTools.extendEnum(PrimitiveNumber))
@:
enum abstract PrimitiveType(String) to String 
{
    
var STRING = "STRING";
    
var BOOL   = "BOOL";
}

@:build(AbstractTools.extendEnum(PrimitiveNumber))
@:build(AbstractTools.extendEnum(PrimitiveType))
@:
enum abstract Type(String) to String 
{
    
var OBJECT = "OBJECT";
    
var LIST   = "LIST";
    
var MAP    = "MAP";
    
var ENUM   = "ENUM";
}

But it isn't a really good solution  I think...

Do you know an other way?
Reply all
Reply to author
Forward
0 new messages