9.5.1 Enum building

Building enums is analogous to building classes with a simple mapping:

  • Enum constructors without arguments are variable fields FVar.
  • Enum constructors with arguments are method fields FFun.
import haxe.macro.Context;
import haxe.macro.Expr;

class EnumBuildingMacro {
  macro static public function build():Array<Field> {
    var noArgs = makeEnumField("A", FVar(null, null));
    var eFunc = macro function(value:Int) {};
    var fInt = switch (eFunc.expr) {
      case EFunction(_, f): f;
      case _: throw "false";
    }
    var intArg = makeEnumField("B", FFun(fInt));
    return [noArgs, intArg];
  }

  static function makeEnumField(name, kind) {
    return {
      name: name,
      doc: null,
      meta: [],
      access: [],
      kind: kind,
      pos: Context.currentPos()
    }
  }
}
@:build(EnumBuildingMacro.build())
enum E {}

class Main {
  static public function main() {
    switch (E.A) {
      case A:
      case B(v):
    }
  }
}

Because enum E is annotated with a :build metadata, the called macro builds two constructors A and B "into" it. The former is added with the kind being FVar(null, null), meaning it is a constructor without argument. For the latter, we use reification to obtain an instance of haxe.macro.Expr.Function with a singular Int argument.

The main method proves the structure of our generated enum by matching it. We can see that the generated type is equivalent to this:

enum E {
    A;
    B(value:Int);
}