macros - 通用建筑枚举的一些错误

标签 macros haxe

已解决 对于有史以来第一个编写宏的人来说,这并不是最简单的。但我学到了很多东西,对 Gama11 给予了我很多荣誉,他为我指明了正确的方向,还有这样一个美丽事物的核心团队:Haxe。

我什至添加了一些灵活的文档字段字符串,因此您可以在自动完成期间获得很好的信息。 enter image description here enter image description here enter image description here

主.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');

要么.hx

package;

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

/*@:genericbuild only works on classes, but 
can still override the class with an enum. Funky. */

EitherMacro.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 使用美化模式在转储子目录中转储键入 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

关于macros - 通用建筑枚举的一些错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57481810/

相关文章:

haxe - 基于Haxe编译器版本的条件编译?

haxelib run 无法启动新线程?

actionscript-3 - 任何 Haxe GC 提示?

c - 将宏参数强制为特定类型

c - X-宏 : how to make the list of variables compile-time configurable?

macros - Haxe宏: quote field properly

Haxe:如何防止未使用的类被淘汰

c - 如何在 C 中使用宏连接两个宽字符串?

excel - VBA:比较两个记录集并返回记录集 1 中可用且记录集 2 中不可用的记录

c - 为什么宏函数不是按值调用?