繁体   English   中英

泛型构建枚举的一些错误

[英]Some errors with genericbuilding enums

已解决对于第一个编写此宏的宏来说,这并不是最简单的。 但是我学到了很多东西,非常感谢 Gama11,他为我指明了正确的方向,以及这样一个美丽事物的核心团队:Haxe。

我什至添加了一些漂亮的文档字段字符串,因此您可以在自动完成过程中获得不错的信息。 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

主文件

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. */

要么宏.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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM