Как вернуть экземпляр класса с помощью макроса выражения? - PullRequest
0 голосов
/ 18 февраля 2020

Код драйвера

//---------------- Main.hx ------------------------------------------------------------------
import core.reflection.ReflectionTools;
import core.SomeClass;
class Main{
   public static function main(){
      var s = new SomeClass();
      ReflectionTools.info(s);
   }
}

Макрос

//---------------- ReflectionTools.hx -----------------------------------------------------
class RelectionTools {
    public static macro function info(obj:Expr):Expr{
        var pos = Context.currentPos();
        var block = [];
        var result:Dynamic;
        var type:Type=Context.typeof(obj);        
        result=(switch(type){
            case TInst(t, params):new RelectionClass(t, params);
            case TEnum(t, params):new ReflectionEnum(t, params);
            case TDynamic(t):new ReflectionDynamic(t);
            case TFun(args, ret):new ReflectionFunction(args, ret);
            case TMono(t):new ReflectionMonomorph(t);
            case TLazy(f):new ReflectionLazy(f);
            case TAbstract(t, params):new ReflectionAbstract(t, params);
            case TType(t, params):new ReflectionTypeDefinition(t, params);
            case TAnonymous(a):new ReflectionAnonymousStructure(a);
        });
        return $v{result};
    }
}

Компилятор Haxe:

Ожидается Expr, но получен core.reflection.RelectionClass (см. Dump / decoding_error.txt для деталей)

Ответы [ 2 ]

1 голос
/ 25 февраля 2020

Это не макрос сборки (который позволяет возвращать экземпляры классов), но это макрос выражения. Лучший способ имитировать функциональность класса c - использовать тезисы.

/* Solution Description
1. a custom Json abstract with underlying type {} and with implicit   
    casts to underlying type. See Json.hx
2. abstracts which reflect possible Type enums with underlying custom 
   Json abstract and forwards. See example ReflectionPrimitive.hx
   and mimic inheritance by underlying types as superclass 
   see example ReflectionFunction.hx 
3. uses same instantiation code as original class instantiation 
   but now they are abstracts (see PROBLEM(The macro). Solved! */

Шаг 1.
пользовательский Json реферат с базовым типом {} и неявным приведением к базовому типу.

// ---------------- Json.hx ----------------------------------------------
package core.ds.json;
import haxe.Serializer;
import haxe.Unserializer;
import haxe.Json as J;

abstract Json({}) from ({}) to ({}) {
    public inline function new(?data:{}){
        this=data;
        if(this==null){
            this={};
        }
    }
    @:arrayAccess 
    public inline function get(key:String):Dynamic{
        if(exists(key)){
            return Reflect.field(this,key);
        } 
        return null;
    }
    @:arrayAccess 
    public inline function set(key:String, value:Dynamic):Dynamic{
        Reflect.setField(this, key, value);
        return value;
    }   

    public inline function isEmpty(key:String):Bool{
        return !isSet(key) || (exists(key) && (  get(key)=="" || get(key)==''|| get(key)==null || get(key)==0  ));
    }

    public inline function isSet(key:String):Bool{
        return exists(key) && get(key)!=null;
    }

    public inline function exists(key:String):Bool {
        return Reflect.hasField(this, key);
    } 
    @:to
    public inline function toMap():Map<String, Dynamic>{
        var result:Map<String, Dynamic>=new Map<String, Dynamic>();
        var fields:Array<String>=Reflect.fields(this);
        for (f in fields){
            result.set(f, Reflect.field(this, f));
        }
        return result;
    }
    @:to
    public inline function toJsonString():String{
        return J.stringify(this,null," ");
    }

    public inline function values():Array<Dynamic>{
        var result:Array<Dynamic>=[];
        var keys:Array<String>=keys();
        for(k in keys){
            result.push(Reflect.field(this,k));
        }
        return result;
    }

    public inline function keys():Array<String>{
        return Reflect.fields(this);
    }

    public inline function clone():Json{
        return Unserializer.run(Serializer.run(this));
    }

    public var length(get,never):Int;


    private inline function get_length():Int{
        return keys().length;
    }

    public inline function keyValueIterator():KeyValueIterator<String, Dynamic>{
        return toMap().keyValueIterator();
    }


    @:from 
    public static function fromJsonString(json:String):Json{
        return J.parse(json);
    }
    @:from 
    public static function fromMap(map:Map<String, Dynamic>):Json{
        var result={};
        for (k=>v in map){
            Reflect.setField(result, k, v);
        }
        return result;
    }

}

Шаг 2.
рефераты, отражающие возможные перечисления типов с базовыми пользовательскими Json аннотациями и вперед. См. Пример ReflectionPrimitive.hx и наследование mimi c базовыми типами как суперкласс. См. Пример ReflectionFunction.hx

//---------------- ReflectionPrimitive.hx ----------------------------------------------

@:forward()
abstract ReflectionPrimitive(core.ds.json.Json) from core.ds.json.Json to core.ds.json.Json{
    public inline function new(nameType:String){
        this=new core.ds.json.Json({data:new core.ds.json.Json(), info:new core.ds.json.Json({nameType:nameType})});
    }
    public var data(get, set):core.ds.json.Json;
    public var info(get, set):core.ds.json.Json;
    private function get_data():core.ds.json.Json {
        return this["data"];
    }
    private function set_data(value:core.ds.json.Json):core.ds.json.Json {
        this["data"]=value;
        return this;
    }
    private function get_info():core.ds.json.Json {
        return this["info"];
    }
    private function set_info(value:core.ds.json.Json):core.ds.json.Json {
        this["info"]=value;
        return this;
    }
 }

Имитация наследования

//---------------- ReflectionFunction.hx ----------------------------------------------
@:forward(data, info, get, isEmpty, isSet, exists, toMap, toJsonString, values, keys, clone, length, keyValueIterator, fromJsonString, fromMap)
abstract ReflectionFunction(ReflectionPrimitive) from ReflectionPrimitive to ReflectionPrimitive{
    public inline function new(args:Array<{t:Type, opt:Bool, name:String}>, ret:Type){
        this=new ReflectionPrimitive(NameType.FUNCTION);
        var newArgs=new Array<core.ds.json.Json>();
        for(a in args){
           newArgs.push(new core.ds.json.Json(a));
        }
        this.data=this.data.set("args",newArgs).set("ret", ret);
    }
    public var args(get, never):Array<core.ds.json.Json>;
    public var ret(get,never):Type;

    private function get_args():Array<core.ds.json.Json>{
        return this.data.get("args");
    }
    private function get_ret():Type{
        return this.data.get("ret");
    }

}

Оставьте макрос без изменений, теперь он будет работать.

1 голос
/ 18 февраля 2020

Макрос - это функция времени компиляции, а не функция времени выполнения, вы не можете вернуть экземпляр класса. Вместо этого вы должны вернуть выражение, которое создает новый экземпляр (у меня нет ваших классов, поэтому я использую здесь мой класс)

var type=Context.typeof(obj); 
return (switch(type){
    case TInst(t, params):macro new MyClass();//RelectionClass(t, params);
    case TEnum(t, params):macro new MyClass();//ReflectionEnum(t, params);
    case TDynamic(t):macro new MyClass();//ReflectionDynamic(t);
    case TFun(args, ret):macro new MyClass();//ReflectionFunction(args, ret);
    case TMono(t):macro new MyClass();//ReflectionMonomorph(t);
    case TLazy(f):macro new MyClass();//ReflectionLazy(f);
    case TAbstract(t, params):macro new MyClass();//ReflectionAbstract(t, params);
    case TType(t, params):macro new MyClass();//ReflectionTypeDefinition(t, params);
    case TAnonymous(a):macro new MyClass();//ReflectionAnonymousStructure(a);
});
return macro null;
...