[macro] add ClassProvideMacro

This commit is contained in:
2019-11-18 18:00:55 +03:00
parent 74ed2d4425
commit 7a5b32b251
16 changed files with 100 additions and 54 deletions

View File

@@ -1,5 +1,6 @@
package demo;
import haxework.provider.Provider;
import demo.dispatch.DemoDispatcher;
import demo.popup.ColorPopup;
import demo.popup.FontPopup;
@@ -45,6 +46,8 @@ class Demo extends App implements DemoListener {
public static function main() {
L.push(new TraceLogger());
trace("!", Provider.instance.factories);
var app = new Demo(new AppTheme());
app.resources.image.put("logo", HaxeLogo.resolve());
app.start(new DemoView());

View File

@@ -4,10 +4,6 @@ import flash.Lib;
import haxework.animate.Animate;
import haxework.animate.FadeAnimate;
import haxework.animate.UnFadeAnimate;
import haxework.net.manage.ILoaderManager;
import haxework.net.manage.LoaderManager;
import haxework.resources.IResources;
import haxework.resources.Resources;
import haxework.view.IView;
import haxework.view.popup.PopupManager;
import haxework.view.Root;
@@ -17,15 +13,10 @@ class App {
@:provide var app:App;
@:provide var theme:ITheme;
@:provide var resources:IResources;
@:provide var loaderManager:ILoaderManager;
@:provide var popupManager:PopupManager;
public function new(?theme:ITheme) {
this.theme = theme;
resources = new Resources();
loaderManager = new LoaderManager();
popupManager = new PopupManager();
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v);
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v);
app = this;

View File

@@ -0,0 +1,20 @@
package haxework.macro;
import haxe.macro.Expr;
import haxe.macro.Type;
class ClassProvideMacro extends ClassTypeMacro {
public static var bundle(default, null):Array<{key: ClassType, value: ClassType}> = [];
public function new() {
super(":provide");
}
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
var meta = MacroUtil.getClassMeta(classType, metaName);
var valueType = meta.params.length == 0 ? classType : MacroUtil.getExprClassType(meta.params[0]);
bundle.push({key: classType, value: valueType});
return super.apply(classType, fields);
}
}

View File

@@ -23,10 +23,7 @@ class DispatcherMacro extends ClassTypeMacro {
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
var result:Array<Field> = fields.slice(0);
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
var type:ClassType = switch Context.getType(typeName) {
case TInst(t, _): t.get();
case _: null;
}
var type:ClassType = MacroUtil.getExprClassType(classType.meta.extract(metaName)[0].params[0]);
var fields = type.fields.get();
for (field in fields) {
var argsTypes:Array<Type> = switch field.type {

View File

@@ -2,7 +2,7 @@ package haxework.macro;
import haxe.macro.Expr;
using haxework.macro.Util;
using haxework.macro.MacroUtil;
class FieldMacro {
public var metaName(default, null):String;

View File

@@ -1,9 +1,11 @@
package haxework.macro;
import haxe.macro.Context;
import haxe.macro.ExprTools;
import haxe.macro.Expr;
import haxe.macro.Type;
class Util {
class MacroUtil {
public static function getMetaParams(meta:MetadataEntry):Array<String> {
return meta.params.map(function(param:Expr) return switch param.expr {
@@ -17,15 +19,21 @@ class Util {
}
public static function getClassMeta(classType:ClassType, metaName:String):Null<MetadataEntry> {
for (md in classType.meta.get()) if (md.name == metaName) {
return md;
for (meta in classType.meta.get()) {
if (meta.name == metaName) {
return meta;
}
}
return null;
}
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
for (md in field.meta) if (md.name == metaName) {
return md;
if (field.meta != null) {
for (meta in field.meta) {
if (meta.name == metaName) {
return meta;
}
}
}
return null;
}
@@ -48,4 +56,12 @@ class Util {
public static function getField(fields:Array<Field>, name:String):Null<Field> {
return Lambda.find(fields, function(field:Field):Bool return field.name == name);
}
public static function getExprClassType(expr:Expr):Null<ClassType> {
var typeName = ExprTools.toString(expr);
return switch Context.getType(typeName) {
case TInst(t, _): t.get();
case _: null;
}
}
}

View File

@@ -3,7 +3,7 @@ package haxework.macro;
import haxe.macro.Context;
import haxe.macro.Expr;
using haxework.macro.Util;
using haxework.macro.MacroUtil;
class ProvideMacro extends FieldMacro {
@@ -22,7 +22,7 @@ class ProvideMacro extends FieldMacro {
case TPath(p): p.name;
default: null;
}
var provideType:String = meta.params.length == 0 ? null : Util.getExprString(meta.params[0].expr);
var provideType:String = meta.params.length == 0 ? null : MacroUtil.getExprString(meta.params[0].expr);
var isStatic = Lambda.exists(field.access, function(a: Access) return a == AStatic);
field.kind = FProp('get', 'set', type);
var access = [APrivate, AInline];
@@ -35,7 +35,7 @@ class ProvideMacro extends FieldMacro {
pos: field.pos,
kind: FFun({
args: [],
expr: Context.parse('return haxework.provider.Provider.get(${args.join(',')})', field.pos),
expr: Context.parse('return haxework.provider.Provider.instance.get(${args.join(',')})', field.pos),
params: [],
ret: type,
})
@@ -47,7 +47,7 @@ class ProvideMacro extends FieldMacro {
pos: field.pos,
kind: FFun({
args: [{name: 'value', type: type}],
expr: Context.parse('{haxework.provider.Provider.set(${args.join(',')}); return value;}', field.pos),
expr: Context.parse('{haxework.provider.Provider.instance.set(${args.join(',')}); return value;}', field.pos),
params: [],
ret: type,
})

View File

@@ -1,6 +1,6 @@
package haxework.macro;
using haxework.macro.Util;
using haxework.macro.MacroUtil;
class ResourceMacro extends FieldMacro {

View File

@@ -5,7 +5,7 @@ import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.ComplexTypeTools;
using haxework.macro.Util;
using haxework.macro.MacroUtil;
using haxe.macro.MacroStringTools;
typedef TProperty<T> = {
@@ -162,11 +162,11 @@ class StyleMacro extends ClassTypeMacro {
}
for (field in properties) {
var propertyName = 'theme_${field.name}';
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
expr.push(macro $i{propertyName} = haxework.provider.Provider.instance.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
}
for (field in styleds) {
var propertyName = '${field.name}';
expr.push(macro $i{propertyName} = haxework.provider.Provider.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
expr.push(macro $i{propertyName} = haxework.provider.Provider.instance.get(haxework.view.theme.ITheme).resolve((styleKey!=null?(styleKey+"."):"")+$v{field.name}, style));
}
if (hasOnStyle) {
expr.push(macro onStyle());

View File

@@ -6,7 +6,7 @@ import haxe.macro.Type;
import haxework.macro.PositionJsonParser;
import Lambda;
using haxework.macro.Util;
using haxework.macro.MacroUtil;
class TemplateMacro extends ClassTypeMacro {
@@ -46,7 +46,7 @@ class TemplateMacro extends ClassTypeMacro {
a[2];
}
case "resource" | "r":
var bindExpr = 'haxework.provider.Provider.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
var bindExpr = 'haxework.provider.Provider.instance.get(haxework.resources.IResources).${a[1]}.bind("${a[2]}", ${name}, "${key}")';
exprs.push(Context.parse(bindExpr, getPosition(position)));
null;
case "translate" | "t":
@@ -182,12 +182,11 @@ class TemplateMacro extends ClassTypeMacro {
private static function findViewsBindings(fields:Array<Field>):Map<String, String> {
var result:Map<String, String> = new Map();
for (field in fields) if (field.meta != null) {
for (meta in field.meta) {
if (meta.name == ':view') {
var viewId:String = meta.params.length == 0 ? field.name : Util.getExprString(meta.params[0].expr);
result.set(viewId, field.name);
}
for (field in fields) {
var viewMeta = field.getFieldMeta(":view");
if (viewMeta != null) {
var viewId:String = viewMeta.params.length == 0 ? field.name : MacroUtil.getExprString(viewMeta.params[0].expr);
result.set(viewId, field.name);
}
}
return result;
@@ -196,7 +195,7 @@ class TemplateMacro extends ClassTypeMacro {
override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
i = 0;
var meta = classType.getClassMeta(metaName);
var params = Util.getMetaParams(meta);
var params = MacroUtil.getMetaParams(meta);
var filePath = params[0];
if (filePath == null) {
filePath = classType.pack.join("/") + "/" + classType.name + ".yaml";

View File

@@ -1,10 +1,10 @@
package haxework.net.manage;
interface ILoaderManager {
@:provide(LoaderManager) interface ILoaderManager {
public var actives(default, null):Array<ILoader<Dynamic>>;
public var queue(default, null):Array<ILoader<Dynamic>>;
public var limit(default, default):Int;
public function add(loader:ILoader<Dynamic>):Void;
public function release(loader:ILoader<Dynamic>):Void;
}
}

View File

@@ -4,6 +4,7 @@ import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import haxe.macro.TypeTools;
import haxework.macro.ClassProvideMacro;
import haxework.macro.ClassTypeMacro;
import haxework.macro.DispatcherMacro;
import haxework.macro.FieldMacro;
@@ -16,6 +17,7 @@ import haxework.macro.TemplateMacro;
class Parser {
private static var classTypeMacros:Array<ClassTypeMacro> = [
new ClassProvideMacro(),
new TemplateMacro(),
new DispatcherMacro(),
new StyleMacro(),

View File

@@ -15,7 +15,7 @@ abstract KeyType<T>(String) {
}
}
class Provider {
@:singleton class Provider {
private static function key<T>(i:KeyType<T>, ?type:Dynamic):String {
var result:String = Std.string(i);
@@ -23,22 +23,40 @@ class Provider {
return result;
}
private static var factories:Map<String, Class<Dynamic>> = new Map();
private static var args:Map<String, Array<Dynamic>> = new Map();
private static var instances:Map<String, Dynamic> = new Map();
public var factories:Map<String, Class<Dynamic>>;
private var args:Map<String, Array<Dynamic>>;
private var instances:Map<String, Dynamic>;
public static function setFactory<T>(i:KeyType<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void {
var key = key(i, type);
factories.set(key, clazz);
if (args != null) Provider.args.set(key, args);
public function new() {
factories = new Map();
args = new Map();
instances = new Map();
resolveDefaultFactories();
}
public static function set<T>(i:KeyType<T>, instance:T, ?type:Dynamic):Void {
macro static function resolveDefaultFactories() {
var result = [];
for (item in haxework.macro.ClassProvideMacro.bundle) {
// ToDo: ClassType to Expr?
var k = haxe.macro.Context.parse(haxe.macro.MacroStringTools.toDotPath(item.key.pack, item.key.name), haxe.macro.Context.currentPos());
var v = haxe.macro.Context.parse(haxe.macro.MacroStringTools.toDotPath(item.value.pack, item.value.name), haxe.macro.Context.currentPos());
result.push(macro setFactory(${k}, ${v}));
}
return macro $b{result};
}
public function setFactory<T>(i:KeyType<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void {
var key = key(i, type);
factories.set(key, clazz);
if (args != null) this.args.set(key, args);
}
public function set<T>(i:KeyType<T>, instance:T, ?type:Dynamic):Void {
var key = key(i, type);
instances.set(key, instance);
}
public static function get<T>(i:KeyType<T>, ?type:Dynamic):T {
public function get<T>(i:KeyType<T>, ?type:Dynamic):T {
var key = key(i, type);
if (instances.exists(key)) {
return instances.get(key);
@@ -52,7 +70,7 @@ class Provider {
}
}
public static function build<T>(i:Class<T>, ?type:Dynamic):T {
public function build<T>(i:Class<T>, ?type:Dynamic):T {
var key = key(i, type);
if (factories.exists(key)) {
var instance:T = Type.createInstance(factories.get(key), args.exists(key) ? args.get(key) : []);
@@ -62,7 +80,7 @@ class Provider {
}
}
public static function setProperty<T>(i:Class<T>, field:String, value:Dynamic, ?type:Dynamic):Void {
public function setProperty<T>(i:Class<T>, field:String, value:Dynamic, ?type:Dynamic):Void {
var o:Dynamic = get(i, type);
if (o != null && Reflect.hasField(o, field)) {
Reflect.setProperty(o, field, value);

View File

@@ -2,9 +2,9 @@ package haxework.resources;
import flash.display.BitmapData;
import flash.display.MovieClip;
import haxework.resources.Resources.ResMap;
import haxework.resources.Resources;
interface IResources {
@:provide(Resources) interface IResources {
public var image(default, null):ResMap<BitmapData>;
public var color(default, null):ResMap<Int>;
public var movie(default, null):ResMap<MovieClip>;

View File

@@ -30,7 +30,7 @@ class Root {
this.autoSize = autoSize;
Lib.current.addChild(view.content);
if (Std.is(view, IGroupView)) {
Provider.set(IGroupView, cast view);
Provider.instance.set(IGroupView, cast view);
}
var content:DisplayObject = view.content;
if (content.stage == null) {

View File

@@ -5,7 +5,7 @@ import haxework.animate.IAnimate;
typedef P = PopupView<Dynamic>;
class PopupManager {
@:provide class PopupManager {
public var showAnimateFactory(default, default):IView<Dynamic> -> IAnimate;
public var closeAnimateFactory(default, default):IView<Dynamic> -> IAnimate;