宏来填写自定义@:enum摘要的字段名称,值和switch语句?

时间:2016-02-11 14:33:04

标签: macros haxe

我有一个独特的情况。出于各种原因,主要是与可以为空的stringly typed遗留系统进行互操作,以及我目前不会进入的各种其他需求,我已经确定了一个自定义的@:enum摘要,看起来像这样:

@:enum abstract MyEnum(Null<Int>) {

    public var A = 0;
    public var B = 1;
    public var C = 2;
    public var D = 3;
    public var E = 4;
    public var F = 5;
    public var G = 6;

    @:from private static function fromString (value:String):MyEnum {

        return switch (value) {

            case "a": A;
            case "b": B;
            case "c": C;
            case "d": D;
            case "e": E;
            case "f": F;
            case "g": G;
            default: null;

        }

    }

    @:to private static function toString (value:Int):String {

        return switch (value) {

            case A: "a";
            case B: "b";
            case C: "c";
            case D: "d";
            case E: "e";
            case F: "f";
            case G: "g";
            default: null;

        }

    }

}

然而,这需要输入大量令人讨厌的东西,并且在添加和删除成员时,很容易发生手动错误。显然,这遵循一个超级可预测的模式,用宏来构造似乎是一件好事,但我对haxe宏很糟糕。

有人可以解释我如何使用宏来构建这个枚举,以便我所提供的只是一个字段名列表吗?

伪代码:

@:enum abstract MyEnum = doTheMacroMagic(["A","B","C","D","E","F","G"]);

逻辑步骤是:

  • 从字段名称(大写)
  • 声明公共变量
  • 从字段名称(小写)
  • 声明fromString / toString值
  • 将公共变量设置为基于0的整数,并按照与提供字段名称相同的顺序

我认为像这样一个简单的实际例子可能最终使haxe宏&#34;点击&#34;对我来说,如果我能在行动中看到它。

1 个答案:

答案 0 :(得分:2)

Flixel处理类似于FlxKeyFlxMacroUtil.buildMap()的类的用例。此表达式宏查找它在摘要中找到的所有大写内联变量并从中生成Map<String, EnumType>,其中键是字段名称,值是字段值(或者如果{{1}则相反}是invert)。

true

我认为这是一个很好的起点。如果您想要生成整个@:enum abstract FlxKey(Int) from Int to Int { public static var fromStringMap(default, null):Map<String, FlxKey> = FlxMacroUtil.buildMap("flixel.input.keyboard.FlxKey"); public static var toStringMap(default, null):Map<FlxKey, String> = FlxMacroUtil.buildMap("flixel.input.keyboard.FlxKey", true); var A = 65; var B = 66; // more keys... @:from public static inline function fromString(s:String) { s = s.toUpperCase(); return fromStringMap.exists(s) ? fromStringMap.get(s) : NONE; } @:to public inline function toString():String { return toStringMap.get(this); } } ,则需要abstract宏。

回答后续问题,如何生成字段:使用构建宏实际上非常简单:

@:build

@:enum @:build(Macro.createVariables(["A", "B", "C", "D", "E"])) abstract Generated(Int) { } (明智地拥有自己的文件以避免处理Macro.hx条件):

#if macro

您会注意到package; import haxe.macro.Context; import haxe.macro.Expr; class Macro { public static macro function createVariables(varNames:Array<String>):Array<Field> { // get the current fields of the calling type (empty array in this case) var fields = Context.getBuildFields(); for (i in 0...varNames.length) // create a custom variable and add it to the fields fields.push(createVariable(varNames[i], i)); return fields; } private static function createVariable(name:String, value:Int):Field { return { name: name, doc: null, meta: [], access: [Access.APublic, Access.AStatic, Access.AInline], kind: FieldType.FVar(macro:Int, macro $v{value}), pos: Context.currentPos() } } } 自动完成中显示的字段。您还可以通过在执行AST转储时查看Generated.来查看生成的内容。