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

View File

@@ -4,10 +4,6 @@ import flash.Lib;
import haxework.animate.Animate; import haxework.animate.Animate;
import haxework.animate.FadeAnimate; import haxework.animate.FadeAnimate;
import haxework.animate.UnFadeAnimate; 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.IView;
import haxework.view.popup.PopupManager; import haxework.view.popup.PopupManager;
import haxework.view.Root; import haxework.view.Root;
@@ -17,15 +13,10 @@ class App {
@:provide var app:App; @:provide var app:App;
@:provide var theme:ITheme; @:provide var theme:ITheme;
@:provide var resources:IResources;
@:provide var loaderManager:ILoaderManager;
@:provide var popupManager:PopupManager; @:provide var popupManager:PopupManager;
public function new(?theme:ITheme) { public function new(?theme:ITheme) {
this.theme = theme; this.theme = theme;
resources = new Resources();
loaderManager = new LoaderManager();
popupManager = new PopupManager();
popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v); popupManager.showAnimateFactory = function(v) return new UnFadeAnimate(v);
popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v); popupManager.closeAnimateFactory = function(v) return new FadeAnimate(v);
app = this; 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> { override public function apply(classType:ClassType, fields:Array<Field>):Array<Field> {
var result:Array<Field> = fields.slice(0); var result:Array<Field> = fields.slice(0);
var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]); var typeName = ExprTools.toString(classType.meta.extract(metaName)[0].params[0]);
var type:ClassType = switch Context.getType(typeName) { var type:ClassType = MacroUtil.getExprClassType(classType.meta.extract(metaName)[0].params[0]);
case TInst(t, _): t.get();
case _: null;
}
var fields = type.fields.get(); var fields = type.fields.get();
for (field in fields) { for (field in fields) {
var argsTypes:Array<Type> = switch field.type { var argsTypes:Array<Type> = switch field.type {

View File

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

View File

@@ -1,9 +1,11 @@
package haxework.macro; package haxework.macro;
import haxe.macro.Context;
import haxe.macro.ExprTools;
import haxe.macro.Expr; import haxe.macro.Expr;
import haxe.macro.Type; import haxe.macro.Type;
class Util { class MacroUtil {
public static function getMetaParams(meta:MetadataEntry):Array<String> { public static function getMetaParams(meta:MetadataEntry):Array<String> {
return meta.params.map(function(param:Expr) return switch param.expr { 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> { public static function getClassMeta(classType:ClassType, metaName:String):Null<MetadataEntry> {
for (md in classType.meta.get()) if (md.name == metaName) { for (meta in classType.meta.get()) {
return md; if (meta.name == metaName) {
return meta;
}
} }
return null; return null;
} }
public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> { public static function getFieldMeta(field:Field, metaName:String):Null<MetadataEntry> {
for (md in field.meta) if (md.name == metaName) { if (field.meta != null) {
return md; for (meta in field.meta) {
if (meta.name == metaName) {
return meta;
}
}
} }
return null; return null;
} }
@@ -48,4 +56,12 @@ class Util {
public static function getField(fields:Array<Field>, name:String):Null<Field> { public static function getField(fields:Array<Field>, name:String):Null<Field> {
return Lambda.find(fields, function(field:Field):Bool return field.name == name); 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.Context;
import haxe.macro.Expr; import haxe.macro.Expr;
using haxework.macro.Util; using haxework.macro.MacroUtil;
class ProvideMacro extends FieldMacro { class ProvideMacro extends FieldMacro {
@@ -22,7 +22,7 @@ class ProvideMacro extends FieldMacro {
case TPath(p): p.name; case TPath(p): p.name;
default: null; 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); var isStatic = Lambda.exists(field.access, function(a: Access) return a == AStatic);
field.kind = FProp('get', 'set', type); field.kind = FProp('get', 'set', type);
var access = [APrivate, AInline]; var access = [APrivate, AInline];
@@ -35,7 +35,7 @@ class ProvideMacro extends FieldMacro {
pos: field.pos, pos: field.pos,
kind: FFun({ kind: FFun({
args: [], 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: [], params: [],
ret: type, ret: type,
}) })
@@ -47,7 +47,7 @@ class ProvideMacro extends FieldMacro {
pos: field.pos, pos: field.pos,
kind: FFun({ kind: FFun({
args: [{name: 'value', type: type}], 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: [], params: [],
ret: type, ret: type,
}) })

View File

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

View File

@@ -5,7 +5,7 @@ import haxe.macro.Expr;
import haxe.macro.Type; import haxe.macro.Type;
using haxe.macro.ComplexTypeTools; using haxe.macro.ComplexTypeTools;
using haxework.macro.Util; using haxework.macro.MacroUtil;
using haxe.macro.MacroStringTools; using haxe.macro.MacroStringTools;
typedef TProperty<T> = { typedef TProperty<T> = {
@@ -162,11 +162,11 @@ class StyleMacro extends ClassTypeMacro {
} }
for (field in properties) { for (field in properties) {
var propertyName = 'theme_${field.name}'; 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) { for (field in styleds) {
var propertyName = '${field.name}'; 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) { if (hasOnStyle) {
expr.push(macro onStyle()); expr.push(macro onStyle());

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import haxe.macro.Context;
import haxe.macro.Expr; import haxe.macro.Expr;
import haxe.macro.Type; import haxe.macro.Type;
import haxe.macro.TypeTools; import haxe.macro.TypeTools;
import haxework.macro.ClassProvideMacro;
import haxework.macro.ClassTypeMacro; import haxework.macro.ClassTypeMacro;
import haxework.macro.DispatcherMacro; import haxework.macro.DispatcherMacro;
import haxework.macro.FieldMacro; import haxework.macro.FieldMacro;
@@ -16,6 +17,7 @@ import haxework.macro.TemplateMacro;
class Parser { class Parser {
private static var classTypeMacros:Array<ClassTypeMacro> = [ private static var classTypeMacros:Array<ClassTypeMacro> = [
new ClassProvideMacro(),
new TemplateMacro(), new TemplateMacro(),
new DispatcherMacro(), new DispatcherMacro(),
new StyleMacro(), 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 { private static function key<T>(i:KeyType<T>, ?type:Dynamic):String {
var result:String = Std.string(i); var result:String = Std.string(i);
@@ -23,22 +23,40 @@ class Provider {
return result; return result;
} }
private static var factories:Map<String, Class<Dynamic>> = new Map(); public var factories:Map<String, Class<Dynamic>>;
private static var args:Map<String, Array<Dynamic>> = new Map(); private var args:Map<String, Array<Dynamic>>;
private static var instances:Map<String, Dynamic> = new Map(); private var instances:Map<String, Dynamic>;
public static function setFactory<T>(i:KeyType<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void { public function new() {
var key = key(i, type); factories = new Map();
factories.set(key, clazz); args = new Map();
if (args != null) Provider.args.set(key, args); 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); var key = key(i, type);
instances.set(key, instance); 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); var key = key(i, type);
if (instances.exists(key)) { if (instances.exists(key)) {
return instances.get(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); var key = key(i, type);
if (factories.exists(key)) { if (factories.exists(key)) {
var instance:T = Type.createInstance(factories.get(key), args.exists(key) ? args.get(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); var o:Dynamic = get(i, type);
if (o != null && Reflect.hasField(o, field)) { if (o != null && Reflect.hasField(o, field)) {
Reflect.setProperty(o, field, value); Reflect.setProperty(o, field, value);

View File

@@ -2,9 +2,9 @@ package haxework.resources;
import flash.display.BitmapData; import flash.display.BitmapData;
import flash.display.MovieClip; 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 image(default, null):ResMap<BitmapData>;
public var color(default, null):ResMap<Int>; public var color(default, null):ResMap<Int>;
public var movie(default, null):ResMap<MovieClip>; public var movie(default, null):ResMap<MovieClip>;

View File

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

View File

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