解决了
对于第一个要编写的宏,这不是最简单的。但是我对Gama11指出了正确方向的东西学到了很多,很多赞誉,也包括了Haxe这样的美丽事物的核心团队。
而且我什至还添加了一些漂亮的文档字段字符串,因此在自动补全过程中您会获得很好的信息。
macros - 通用建筑枚举的一些错误-LMLPHP
macros - 通用建筑枚举的一些错误-LMLPHP
macros - 通用建筑枚举的一些错误-LMLPHP
Main.hx

var e1:Either<String, Int, Bool> = Either3._1('test');
var e2:Either<String, Int, Bool> = Either3._2(1);
var e3:Either<String, Int, Bool> = Either3._3(true);
var error:Either<String, Int, Bool> = Either3._3('Bool expected, but got a String this will give an error');

任一个
package;

@:genericBuild(EitherMacro.build())
class Either<Rest> {}

/*@:genericbuild only works on classes, but
can still override the class with an enum. Funky. */
要么Macro.hx
package;


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


class EitherMacro {
    static var eitherTypes = new Map<Int,Bool>();

    static function build():ComplexType {
        return switch (Context.getLocalType()) {
            case TInst(_.get() => {name: "Either"}, params):
                buildEitherEnum(params);
            default:
                throw false;
        }
        return macro:Dynamic;
    }

    static function buildEitherEnum(params:Array<Type>):ComplexType {
        var numParams = params.length;
        var name='Either$numParams';
        if (!eitherTypes.exists(numParams)){
            Context.defineType(defineType(name, params));
            eitherTypes[numParams] = true;
        }
        return TPath({pack: [], name: name, params: [for (t in params) TPType(t.toComplexType())]});
    }

    private static inline function defineType(name:String, params:Array<Type>){
        var typeParams:Array<TypeParamDecl> = [];
        var typeStrings:Array<String>=[];
        var numParams = params.length;
        var fields:Array<Field>=[];
        for (i in 0...numParams) {
            var t=i+1;
            typeStrings.push(params[i].toString());
        }
        var constDocStr=typeStrings.join(',');
        for (i in 0...numParams) {
            var t=i+1;
            var typeString:String=typeStrings[i];
            typeParams.push({name:'T$t'});

            fields.push(
                {
                    name:   '_$t',
                    pos:    Context.currentPos(),

                    doc: 'from $name<$constDocStr> _$t(v: $typeString)',
                    kind:FFun({
                            ret: null,
                            params: [{name:'T$t'}],
                            expr: null,
                            args: [
                                {
                                    name: 'v',
                                    type: TPath(
                                        {
                                        name:'T$t',
                                        params:[],
                                        pack:[]
                                        }
                                    )
                                }
                                ]
                        }
                    )
                }
            );
        }
        var docStr:String="Either represents values which are either of type ";
        for(k in 0...typeStrings.length){
            if(k!=typeStrings.length-1){
                docStr+=typeStrings[k]+" or ";
            } else {
                docStr+=typeStrings[k]+".";
            }
        }

        return {
            pack:[],
            name:name,
            pos:Context.currentPos(),
            doc:docStr,
            isExtern: false,
            meta:null,
            kind:TDEnum,
            fields:fields,
            params:typeParams
        }
    }
}
#end
调试宏的简单方法
-D dump = pretty的用法,使用美化模式在dump子目录中键入AST。 dump = pretty的输出与常规的Haxe代码几乎没有区别。出现错误时,您会在转储目录的根目录中找到一个名为“decoding_error.txt”的文件。其内容可能如下所示:
{
    doc: null
    fields: null <- expected value
    isExtern: null
    kind: null <- expected value
    meta: null
    name: null <- expected value
    pack: null <- expected value
    params: null
    pos: null <- expected value
}
line 3: expected value
line 5: expected value
line 7: expected value
line 8: expected value
line 10: expected value
这使我更容易调试。但是更好的方法是方法简单...要调试最简单的方法,请转到宏文件(在我的情况下为EitherMacro.hx)并执行
class EitherMacro{
   public static function build(){
      var fields=Context.getBuildFields();
      var type=Context.getLocalType();
      trace(type);
      for(f in fields){
         trace(f);
      }

      // your other code
/*
If you use @:build)() instead of @:genericbuild
to debug. Make sure the buildfunction returns
Array<Field> and put at the last line

return Context.getBuildFields();

if you use @:genericbuild you must return
ComplexType, and you can add as the line
return macro:Dynamic; if you have no working return yet.
*/


   }
}

输出可能如下所示:
source/EnumBuilder2.hx:18: TEnum(SomeEnum,[TInst(SomeEnum.T1,[]),TInst(SomeEnum.T2,[]),TInst(SomeEnum.T3,[])])


source/EnumBuilder2.hx:20: {name: _1, doc: null, pos: #pos(source/SomeEnum.hx:4: characters 5-14), access: [], kind: FFun({ret: null, params: [], expr: null, args: [{name: v, opt: false, meta: [], type: TPath(<...>), name_pos: #pos((unknown)), value: null}]}), meta: [], name_pos: #pos(source/SomeEnum.hx:4: characters 5-7)}
source/EnumBuilder2.hx:20: {name: _2, doc: null, pos: #pos(source/SomeEnum.hx:5: characters 5-14), access: [], kind: FFun({ret: null, params: [], expr: null, args: [{name: v, opt: false, meta: [], type: TPath(<...>), name_pos: #pos((unknown)), value: null}]}), meta: [], name_pos: #pos(source/SomeEnum.hx:5: characters 5-7)}
source/EnumBuilder2.hx:20: {name: _3, doc: null, pos: #pos(source/SomeEnum.hx:6: characters 5-14), access: [], kind: FFun({ret: null, params: [], expr: null, args: [{name: v, opt: false, meta: [], type: TPath(<...>), name_pos: #pos((unknown)), value: null}]}), meta: [], name_pos: #pos(source/SomeEnum.hx:6: characters 5-7)}
@:genericbuild()的另一个好主意是,首先手动(或任何类型)构造一个枚举,然后使用@:genericbuild对其进行跟踪,或者如果使用@:build出错太多。然后,您可以复制这些跟踪输出,并尝试使用该代码在宏中制作AST。这将大大加快您的开发速度,尤其是在使用复杂宏的情况下。几乎没有脑子;-)

最佳答案

您的宏从未运行过。

用以下代码替换build()函数以进行验证

    static function build():ComplexType {
        trace('build');
        return macro:Dynamic;
    }

我想@:genericBuild仅适用于class

09-25 15:51