11 Commits
0.6.1 ... 0.8.0

Author SHA1 Message Date
086518ae42 [doc] update readme 2018-03-06 22:25:58 +03:00
a53510d1d4 [macro] added @:view macro, refactored @:template macro 2018-03-06 15:44:07 +03:00
4a65cef02a added meta parser 2018-03-05 17:38:11 +03:00
56baf7cfdc fix 2018-02-16 22:20:33 +03:00
97b7686694 [gui] support yaml in builder style 2018-02-15 23:56:46 +03:00
5b4e8dbb5e [gui] change access for item in ListVIew 2018-02-06 10:54:04 +03:00
9671a37d0d [gui] ListViewListener typedef 2018-02-05 22:42:02 +03:00
823f3ea596 [view] added yaml template support 2018-02-05 17:52:58 +03:00
cc6717f46b [provider] ObjectMap -> StringMap 2018-01-26 10:56:38 +03:00
6bc4f297d5 [provider] fix build method 2018-01-25 22:54:36 +03:00
a6bbcb408f [log] fix SocketLogger for flash 2017-12-20 17:50:57 +03:00
20 changed files with 475 additions and 297 deletions

View File

@@ -14,8 +14,8 @@ form.json:
```json ```json
{ {
"type":"haxework.gui.VGroupView", "@type":"haxework.gui.VGroupView",
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xffff00"}, "skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0xffff00"},
"paddings":20, "paddings":20,
"layoutMargin":10, "layoutMargin":10,
"views":[ "views":[
@@ -23,13 +23,13 @@ form.json:
"id":"view1", "id":"view1",
"type":"haxework.gui.SpriteView", "type":"haxework.gui.SpriteView",
"pWidth":100, "pHeight":100, "pWidth":100, "pHeight":100,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0xff0000"} "skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0xff0000"}
}, },
{ {
"id":"view2", "id":"view2",
"type":"haxework.gui.SpriteView", "type":"haxework.gui.SpriteView",
"pWidth":100, "height":50, "pWidth":100, "height":50,
"skin":{"type":"haxework.gui.skin.ColorSkin", "color":"0x00ff00"} "skin":{"@type":"haxework.gui.skin.ColorSkin", "color":"0x00ff00"}
} }
] ]
} }
@@ -37,12 +37,15 @@ form.json:
```haxe ```haxe
@:template("form.json") @:template("form.json")
class FormView extends VGroupView implements ViewBuilder {} class FormView extends VGroupView {
@:view public var view1:IView;
@:view("view2") public var anyVarName:IView;
}
var form = new FormView(); var form = new FormView();
Root.bind(form); // Add form to stage as root view element. Root.bind(form); // Add form to stage as root view element.
trace(form.view1); trace(form.view1);
trace(form.view2); trace(form.anyVarName);
``` ```
## Loader ## Loader

1
extraParams.hxml Normal file
View File

@@ -0,0 +1 @@
--macro haxework.parser.Parser.auto()

View File

@@ -2,13 +2,15 @@
"name": "haxework", "name": "haxework",
"url" : "https://bitbucket.org/shmyga/haxework.git", "url" : "https://bitbucket.org/shmyga/haxework.git",
"license": "BSD", "license": "BSD",
"tags": ["flash"], "tags": ["flash", "openfl"],
"description": "Framework.", "description": "Framework.",
"version": "0.6.1", "version": "0.8.0",
"releasenote": "Update.", "releasenote": "Update.",
"contributors": ["shmyga"], "contributors": ["shmyga"],
"classPath": "src/main", "classPath": "src/main",
"dependencies": { "dependencies": {
"promhx": "" "promhx": "1.1.0",
"openfl": "7.0.0",
"yaml": "1.3.0"
} }
} }

View File

@@ -1,4 +1,9 @@
-cp src -cp src
-lib haxework -cp ../../src/main
-lib yaml
-lib promhx
-main ViewExample.hx -main ViewExample.hx
--macro haxework.parser.Parser.auto()
-swf target/ViewExample.swf -swf target/ViewExample.swf
#-as3 target

View File

@@ -1,12 +1,22 @@
package; package;
import haxework.gui.ViewBuilder; import haxework.gui.View;
import haxework.gui.VGroupView; import haxework.gui.VGroupView;
import haxework.gui.ButtonView; import haxework.gui.ButtonView;
import haxework.gui.Root; import haxework.gui.Root;
@:template("form.json")
class FormView extends VGroupView implements ViewBuilder {} @:template2("form.json")
class FormView extends VGroupView {
@:view public var panel(default, null):View;
@:view public var button1(default, null):View;
@:view public var button2(default, null):View;
@:view public var button3(default, null):View;
private function init() {
trace('Init');
}
}
class ViewExample { class ViewExample {
@@ -15,7 +25,7 @@ class ViewExample {
} }
public function new() { public function new() {
var form = new FormView({listener:this}); var form:FormView = new FormView();
Root.bind(form); Root.bind(form);
trace(form.panel); trace(form.panel);
trace(form.button1); trace(form.button1);

View File

@@ -37,8 +37,7 @@
"width":100, "width":100,
"pHeight":100, "pHeight":100,
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0xcc0000"}, "skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0xcc0000"},
"text":"Text1", "text":"Text1"
"onPress":"@link:listener"
}, },
{ {
"id":"button2", "id":"button2",
@@ -47,8 +46,7 @@
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cc00"}, "skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cc00"},
"text":"Text2", "text":"Text2",
"fontFamily":"Georgia", "fontFamily":"Georgia",
"fontColor":"0xffffff", "fontColor":"0xffffff"
"onPress":"@link:listener"
}, },
{ {
"id":"button3", "id":"button3",
@@ -57,8 +55,7 @@
"skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cccc"}, "skin":{"@type":"haxework.gui.skin.ButtonColorSkin", "color":"0x00cccc"},
"text":"Text 3333333333 ddd", "text":"Text 3333333333 ddd",
"fontFamily":"Tahoma", "fontFamily":"Tahoma",
"fontColor":"0xff0000", "fontColor":"0xff0000"
"onPress":"@link:listener"
} }
] ]
} }

View File

@@ -1,7 +1,7 @@
package haxework.gui; package haxework.gui;
import flash.text.TextField; import flash.text.TextField;
import haxework.gui.IView.Content; import haxework.gui.IView;
import flash.text.TextFormatAlign; import flash.text.TextFormatAlign;
interface ITextView extends IView extends HasPaddings { interface ITextView extends IView extends HasPaddings {

View File

@@ -1,14 +0,0 @@
package haxework.gui;
import haxework.gui.build.Builder;
@:remove @:autoBuild(haxework.gui.ViewBuilderImpl.build())
extern interface ViewBuilder {}
class ViewBuilderImpl {
#if macro
public static function build() {
return new Builder().build();
}
#end
}

View File

@@ -1,193 +0,0 @@
package haxework.gui.build;
#if macro
import haxe.macro.Context;
import haxework.gui.build.PositionJsonParser;
import haxe.macro.Expr;
import haxe.macro.Expr.Field;
class Builder {
private var templateFile:String;
private var templateKey:String;
private var styleFile:String;
private var template:Dynamic;
private var fields:Array<Field>;
private var exprs:Array<Expr>;
private var style:Dynamic;
private var i:Int;
public function new() {
var templateMeta = BuilderUtil.getMeta(":template");
var templatePath = templateMeta[0].split("@");
templateFile = Context.resolvePath(templatePath[0]);
templateKey = templatePath[1];
template = BuilderUtil.loadJsonFile(templateFile);
if (templateKey != null) template = Reflect.field(template, templateKey);
if (templateMeta[1] != null) {
styleFile = Context.resolvePath(templateMeta[1]);
style = BuilderUtil.loadJsonFile(styleFile);
}
fields = Context.getBuildFields();
exprs = [];
i = 0;
}
private function getPosition(?position:JsonKeyPosition):Position {
var min = position == null ? 1 : position.min + 32; // :-(
var max = position == null ? 1 : position.max + 32;
var file = position == null || position.file == null ? templateFile : position.file;
return Context.makePosition({min:min, max:max, file:file});
}
private function specialValue(name:String, key:String, a:Array<String>, position:JsonKeyPosition):Dynamic {
return switch (a[0]) {
case "asset":
switch (a[1]) {
case "image":
"openfl.Assets.getBitmapData(\"" + a[2] + "\")";
case _:
a[2];
}
case "res":
var res = "haxework.provider.Provider.get(haxework.resources.IResources)." + a[1];
var bindExpr = res + ".bind(\"" + a[2] + "\", " + name + ", \"" + key + "\")";
exprs.push(Context.parse(bindExpr, getPosition(position)));
//res + ".get(\"" + a[2] + "\")";
null;
case "locale":
"new haxework.locale.LString(\"" + a[1] + "\")";
case "class":
a[1];
case "layout":
var template = BuilderUtil.loadJsonFile(a[1]);
return getValue(name, key, template, position);
case "link":
"(links == null) ? untyped this : Reflect.field(links, \"" + a[1] + "\")";
case _:
Context.error("Unsupported prefix \"" + a[0] + "\"", getPosition(position));
}
}
private function getValue(name:String, key:String, value:Dynamic, position:JsonKeyPosition):Dynamic {
return if (Std.is(value, Array)) {
value.map(function(v) {
return getValue(null, null, v, position);
});
} else if (Std.is(value, String)) {
if (value.charAt(0) == "@") {
specialValue(name, key, value.substring(1, value.length).split(":"), position);
} else if (~/(0x|#)[A-Fa-f\d]{6}/.match(value)) {
Std.parseInt(StringTools.replace(Std.string(value), "#", "0x"));
} else {
"\"" + value + "\"";
}
} else if (Std.is(value, Float) || (Std.is(value, Bool))) {
value;
} else if (value != null) {
if (Reflect.hasField(value, "@type")) {
var n = "a" + i++;
var type = Reflect.field(value, "@type");
if (type == "Dynamic") {
//ToDo:
exprs.push(Context.parse("var " + n + " = cast {}", getPosition(position)));
} else {
exprs.push(Context.parse("var " + n + " = new " + type + "()", getPosition(position)));
}
createElement(value, n);
n;
} else {
Context.error("Need @type field", getPosition(position));
null;
}
} else {
value;
}
}
private function createElement(template:Dynamic, name:String):String {
if (Reflect.hasField(template, "@style")) {
var s = Reflect.field(style, Reflect.field(template, "@style"));
for (key in Reflect.fields(s)) {
if (key.charAt(0) != "$" && !Reflect.hasField(template, key)) {
Reflect.setField(template, key, Reflect.field(s, key));
Reflect.setField(template, "$" + key, Reflect.field(s, "$" + key));
}
}
}
if (Reflect.hasField(template, "id")) {
var id = Reflect.field(template, "id");
var type = Reflect.field(template, "@type");
var expr = Context.parse("var a:" + type, getPosition());
var complexType = switch (expr.expr) {
case EVars(vars): vars[0].type;
case _: null;
}
fields.push({
name: id,
access: [APublic],
pos: getPosition(),
kind: FProp("default", "null", complexType)
});
exprs.push(Context.parse("this." + id + " = " + name, getPosition()));
}
for (key in Reflect.fields(template)) {
if (key.charAt(0) == "$" || key.charAt(0) == "@") continue;
var position = Reflect.field(template, "$" + key);
var value = getValue(name, key, Reflect.field(template, key), position);
if (value != null) {
exprs.push(Context.parse(name + "." + key + " = " + value, getPosition(position)));
}
}
return name;
}
public function build():Array<Field> {
createElement(template, "this");
var init = false;
for (f in fields) if (f.name == "init") {
init = true;
break;
}
fields.push({
name: "build",
access: [APublic],
pos: getPosition(),
kind: FFun({
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
expr: macro $b{exprs},
params: [],
ret: null
})
});
var contstrExprs = [];
contstrExprs.push(macro super());
contstrExprs.push(macro build(links));
if (init) contstrExprs.push(macro init());
fields.push({
name: "new",
access: [APublic],
pos: getPosition(),
kind: FFun({
args: [{name:"links", type:TPath({name:"Dynamic", pack:[], params:[]}), opt:true, value:null}],
expr: macro $b{contstrExprs},
params: [],
ret: null
})
});
return fields;
}
}
#end

View File

@@ -1,36 +0,0 @@
package haxework.gui.build;
#if macro
import haxe.macro.Context;
import haxe.macro.Expr.Constant;
import haxe.macro.Expr.ExprDef;
class BuilderUtil {
public static function loadJsonFile(path:String) {
Context.registerModuleDependency(Context.getLocalModule(), path);
var content = sys.io.File.getContent(path);
var json = null;
try {
json = PositionJsonParser.parse(content, path);
} catch(error:Dynamic) {
Context.error(error, Context.makePosition({min:0, max:0, file:path}));
}
Context.parse(content, Context.makePosition({min:0, max:0, file:path}));
return json;
}
public static function getMeta(key:String):Array<String> {
var c = Context.getLocalClass().get();
for (meta in c.meta.get()) {
if (meta.name == key) {
return meta.params.map(function(param) return switch(param.expr) {
case ExprDef.EConst(Constant.CString(value)): value;
case _: null;
});
}
}
return [];
}
}
#end

View File

@@ -39,7 +39,7 @@ class ListView<D> extends GroupView implements ScrollListener {
private var mask:SpriteView; private var mask:SpriteView;
private var itemSize:Float; private var itemSize:Float;
private var items:Array<IListItemView<D>>; public var items(default, null):Array<IListItemView<D>>;
private var itemsListeners:Map<IListItemView<D>, MouseEvent->Void>; private var itemsListeners:Map<IListItemView<D>, MouseEvent->Void>;
public function new(layout:ILayout, otherLayout:ILayout) { public function new(layout:ILayout, otherLayout:ILayout) {
@@ -241,7 +241,7 @@ interface IListItemView<D> extends IView {
public var data(default, set):D; public var data(default, set):D;
} }
interface ListViewListener<D> { typedef ListViewListener<D> = {
public function onListItemClick(item:IListItemView<D>):Void; public function onListItemClick(item:IListItemView<D>):Void;
} }

View File

@@ -1,6 +1,6 @@
package haxework.gui.skin; package haxework.gui.skin;
import haxework.gui.IView.Content; import haxework.gui.IView;
interface ISkin<V:IView> { interface ISkin<V:IView> {
public function draw(view:V):Void; public function draw(view:V):Void;

View File

@@ -47,7 +47,7 @@ class SocketLogger extends BaseLogger {
try { try {
var s:String = p.fileName + ":" + p.lineNumber + ": " + text + "\n"; var s:String = p.fileName + ":" + p.lineNumber + ": " + text + "\n";
#if flash #if flash
socket.writeUTF(s); socket.writeUTFBytes(s);
socket.flush(); socket.flush();
#else #else
socket.write(s); socket.write(s);

View File

@@ -0,0 +1,45 @@
package haxework.macro;
import yaml.Parser;
import yaml.Yaml;
import haxe.macro.Context;
class FileUtil {
public static function loadJsonFile(path:String):Dynamic {
Context.registerModuleDependency(Context.getLocalModule(), path);
var content = sys.io.File.getContent(path);
var json = null;
try {
json = PositionJsonParser.parse(content, path);
} catch (error:Dynamic) {
Context.error(error, Context.makePosition({min:0, max:0, file:path}));
}
Context.parse(content, Context.makePosition({min:0, max:0, file:path}));
return json;
}
public static function loadYamlFile(path:String):Dynamic {
Context.registerModuleDependency(Context.getLocalModule(), path);
var content = sys.io.File.getContent(path);
var result = null;
try {
// ToDo: extract poisiton info
result = Yaml.parse(content, Parser.options().useObjects());
} catch (error:Dynamic) {
Context.error(error, Context.makePosition({min:0, max:0, file:path}));
}
//Context.parse(content, Context.makePosition({min:0, max:0, file:path}));
return result;
}
public static function loadFile(path:String):Dynamic {
var ext = path.split('.').pop();
return switch(ext) {
case 'json': loadJsonFile(path);
case 'yml' | 'yaml': loadYamlFile(path);
case x: throw 'Unsupported file format: "${x}"';
}
}
}

View File

@@ -1,4 +1,4 @@
package haxework.gui.build; package haxework.macro;
typedef JsonKeyPosition = { typedef JsonKeyPosition = {
var min:Int; var min:Int;

View File

@@ -0,0 +1,52 @@
package haxework.macro;
import haxe.macro.Context;
import haxe.macro.Expr;
class ProvideMacro {
public static function has(field:Field):Bool {
for (md in field.meta) if (md.name == ":provide") {
return true;
}
return false;
}
private var field:Field;
public function new(field:Field) {
this.field = field;
}
public function apply():Array<Field> {
var result:Array<Field> = [];
var type:ComplexType = switch field.kind {
case FieldType.FVar(t): t;
default: null;
}
var name:String = switch type {
case ComplexType.TPath(p): p.name;
default: null;
}
result.push({
name: field.name,
access: [Access.APublic],
pos: field.pos,
kind: FieldType.FProp('get', 'never', type)
});
result.push({
name: 'get_${field.name}',
access: [Access.APrivate, Access.AInline],
pos: field.pos,
kind: FieldType.FFun({
args: [],
expr: Context.parse('return haxework.provider.Provider.get(${name})', field.pos),
params: [],
ret: type
})
});
return result;
}
}

View File

@@ -0,0 +1,232 @@
package haxework.macro;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import haxework.macro.PositionJsonParser;
class TemplateMacro {
private static inline var metaName:String = ':template';
public static function has(classType:ClassType):Bool {
for (md in classType.meta.get()) if (md.name == metaName) {
return true;
}
return false;
}
private var classType:ClassType;
private var fields:Array<Field>;
private var bindings:Map<String, String>;
private var meta(get, never):MetadataEntry;
private var templateFile:String;
private var template:Dynamic;
private var style:Dynamic;
private var i:Int;
private function get_meta():MetadataEntry {
for (md in classType.meta.get()) if (md.name == metaName) {
return md;
}
return null;
}
public function new(classType:ClassType, fields:Array<Field>) {
this.classType = classType;
this.fields = fields;
var params = Util.getMetaParams(meta);
templateFile = Context.resolvePath(params[0]);
template = FileUtil.loadFile(templateFile);
if (params.length > 1) {
var styleFile = params.length > 1 ? Context.resolvePath(params[1]) : null;
style = FileUtil.loadFile(styleFile);
}
bindings = findViewsBindings(fields);
}
private static function getSpecField(object:Dynamic, field:String):Dynamic {
if (Reflect.hasField(object, "@" + field)) {
return Reflect.field(object, "@" + field);
} else if (Reflect.hasField(object, "$" + field)) {
return Reflect.field(object, "$" + field);
} else {
return null;
}
}
private function getPosition(?position:JsonKeyPosition):Position {
var min = position == null ? 1 : position.min + 32; // :-(
var max = position == null ? 1 : position.max + 32;
var file = position == null || position.file == null ? templateFile : position.file;
return Context.makePosition({min:min, max:max, file:file});
}
private function specialValue(name:String, key:String, a:Array<String>, position:JsonKeyPosition, exprs:Array<Expr>):Dynamic {
return switch (a[0]) {
case "asset":
switch (a[1]) {
case "image":
"openfl.Assets.getBitmapData(\"" + a[2] + "\")";
case _:
a[2];
}
case "res":
var res = "haxework.provider.Provider.get(haxework.resources.IResources)." + a[1];
var bindExpr = res + ".bind(\"" + a[2] + "\", " + name + ", \"" + key + "\")";
exprs.push(Context.parse(bindExpr, getPosition(position)));
//res + ".get(\"" + a[2] + "\")";
null;
case "locale":
"new haxework.locale.LString(\"" + a[1] + "\")";
case "class":
a[1];
case "layout":
var template = FileUtil.loadJsonFile(a[1]);
return createValue(name, key, template, position, exprs);
case "link":
"(links == null) ? untyped this : Reflect.field(links, \"" + a[1] + "\")";
case _:
Context.error("Unsupported prefix \"" + a[0] + "\"", getPosition(position));
}
}
private static function getType(value:Dynamic, position:Position):String {
var type:String = getSpecField(value, "type");
if (type == null) {
Context.error("Need @type field", position);
}
return type;
}
private function createValue(name:String, key:String, value:Dynamic, position:JsonKeyPosition, exprs:Array<Expr>):Dynamic {
return if (Std.is(value, Array)) {
value.map(function(v) {
return createValue(null, null, v, position, exprs);
});
} else if (Std.is(value, String)) {
if (value.charAt(0) == "@" || value.charAt(0) == "$") {
specialValue(name, key, value.substring(1, value.length).split(":"), position, exprs);
} else if (~/(0x|#)[A-Fa-f\d]{6}/.match(value)) {
Std.parseInt(StringTools.replace(Std.string(value), "#", "0x"));
} else {
"\"" + value + "\"";
}
} else if (Std.is(value, Float) || (Std.is(value, Bool))) {
value;
} else if (value != null) {
var type = getType(value, getPosition(position));
if (type != null) {
var n = 'a${i++}';
if (type == "Dynamic") {
//ToDo:
exprs.push(Context.parse("var " + n + " = cast {}", getPosition(position)));
} else {
exprs.push(Context.parse("var " + n + " = new " + type + "()", getPosition(position)));
}
createElement(n, value, exprs);
n;
} else {
null;
}
} else {
value;
}
}
private function createElement(name:String, data:Dynamic, exprs:Array<Expr>):String {
var s = getSpecField(data, "style");
if (s != null) {
var s = Reflect.field(style, s);
for (key in Reflect.fields(s)) {
if (key.charAt(0) != "$" && !Reflect.hasField(data, key)) {
Reflect.setField(data, key, Reflect.field(s, key));
Reflect.setField(data, "$" + key, Reflect.field(s, "$" + key));
}
}
}
if (Reflect.hasField(data, "id")) {
var id = Reflect.field(data, "id");
if (bindings.exists(id)) {
var bind = bindings.get(id);
exprs.push(Context.parse('this.${bind} = ${name}', getPosition()));
}
}
for (key in Reflect.fields(data)) {
if (key.charAt(0) == "$" || key.charAt(0) == "@") continue;
var position = Reflect.field(data, "$" + key);
var value = createValue(name, key, Reflect.field(data, key), position, exprs);
if (value != null) {
exprs.push(Context.parse(name + "." + key + " = " + value, getPosition(position)));
}
}
return name;
}
private function buildBuild(exprs:Array<Expr>):Field {
return {
name: "build",
access: [Access.APrivate],
pos: getPosition(),
kind: FieldType.FFun({
args: [],
expr: macro $b{exprs},
params: [],
ret: null
})
}
}
private function buildConstructor(init:Bool):Field {
var contstrExprs = [];
contstrExprs.push(macro super());
contstrExprs.push(macro build());
if (init) contstrExprs.push(macro init());
return {
name: "new",
access: [Access.APublic],
pos: getPosition(),
kind: FieldType.FFun({
args: [],
expr: macro $b{contstrExprs},
params: [],
ret: null
})
};
}
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 : switch meta.params[0].expr {
case ExprDef.EConst(Constant.CString(value)): value;
default: null;
}
result.set(viewId, field.name);
}
}
}
return result;
}
public function apply():Array<Field> {
i = 0;
var result:Array<Field> = fields.slice(0);
var exprs:Array<Expr> = [];
var init = Lambda.exists(result, function(f) return f.name == 'init');
createElement("this", template, exprs);
result.push(buildBuild(exprs));
result.push(buildConstructor(init));
return result;
}
}

View File

@@ -0,0 +1,18 @@
package haxework.macro;
import haxe.macro.Expr;
class Util {
public static function getMetaParams(meta:MetadataEntry):Array<String> {
return meta.params.map(function(param:Expr) return switch(param.expr) {
case ExprDef.EConst(Constant.CString(value)): value;
case _: null;
});
}
public inline static function DynamicType():ComplexType {
return ComplexType.TPath({name:'Dynamic', pack:[], params:[]});
}
}

View File

@@ -0,0 +1,50 @@
package haxework.parser;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type.ClassType;
import haxe.macro.Type.Ref;
import haxe.macro.Type;
import haxework.macro.ProvideMacro;
import haxework.macro.TemplateMacro;
class Parser {
private static function auto():Void {
haxe.macro.Compiler.addGlobalMetadata("", "@:build(haxework.parser.Parser.autoRun())", true, true, false);
}
private static macro function autoRun():Array<Field> {
var t:Type = Context.getLocalType();
switch (t) {
case null: return null;
case Type.TInst(_.get() => ct, _):
var modify:Bool = false;
var fields:Array<Field> = Context.getBuildFields();
var result:Array<Field> = [];
var appends:Array<Field> = [];
// process fields meta
for (field in fields) {
if (ProvideMacro.has(field)) {
modify = true;
var provide = new ProvideMacro(field);
result = result.concat(provide.apply());
} else {
result.push(field);
}
}
if (modify) {
fields = result;
}
// process class meta
if (TemplateMacro.has(ct)) {
modify = true;
var template = new TemplateMacro(ct, fields);
fields = template.apply();
}
return modify ? fields : null;
default: return null;
}
}
}

View File

@@ -1,30 +1,36 @@
package haxework.provider; package haxework.provider;
import haxe.ds.ObjectMap;
class Provider { class Provider {
//private static var factories:ObjectMap<Dynamic, Class<Dynamic>> = new ObjectMap<Dynamic, Class<Dynamic>>(); private static function key<T>(i:Class<T>, ?type:Dynamic):String {
private static var factories:ObjectMap<Dynamic, Class<Dynamic>> = cast [ var result = Type.getClassName(i);
if (type != null) result += ':${type}';
return result;
}
//private static var factories:Map<String, Class<Dynamic>> = new Map();
private static var factories:Map<String, Class<Dynamic>> = cast [
#if (!neko) #if (!neko)
haxework.net.manage.LoaderManager => haxework.net.manage.ILoaderManager key(haxework.net.manage.LoaderManager) => haxework.net.manage.ILoaderManager
#end #end
]; ];
private static var args:ObjectMap<Dynamic, Array<Dynamic>> = new ObjectMap<Dynamic, Array<Dynamic>>(); private static var args:Map<String, Array<Dynamic>> = new Map();
private static var instances:ObjectMap<Dynamic, Dynamic> = new ObjectMap<Dynamic, Dynamic>(); private static var instances:Map<String, Dynamic> = new Map();
public static function setFactory<T>(i:Class<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void { public static function setFactory<T>(i:Class<T>, clazz:Class<T>, ?type:Dynamic, ?args:Array<Dynamic>):Void {
factories.set(type == null ? i : i + type, clazz); var key = key(i, type);
if (args != null) Provider.args.set(type == null ? i : i + type, args); factories.set(key, clazz);
if (args != null) Provider.args.set(key, args);
} }
public static function set<T>(i:Class<T>, instance:T, ?type:Dynamic):Void { public static function set<T>(i:Class<T>, instance:T, ?type:Dynamic):Void {
instances.set(type == null ? i : i + type, instance); var key = key(i, type);
instances.set(key, instance);
} }
public static function get<T>(i:Class<T>, ?type:Dynamic):T { public static function get<T>(i:Class<T>, ?type:Dynamic):T {
var key:Dynamic = (type == null) ? i : i + type; var key = key(i, type);
if (instances.exists(key)) { if (instances.exists(key)) {
return instances.get(key); return instances.get(key);
} else if (factories.exists(key)) { } else if (factories.exists(key)) {
@@ -32,17 +38,17 @@ class Provider {
instances.set(key, instance); instances.set(key, instance);
return instance; return instance;
} else { } else {
throw "Factory for\" " + i + "\" not found"; throw 'Factory for "${key}" not found';
} }
} }
public static function build<T>(i:Class<T>, ?type:Dynamic):T { public static function build<T>(i:Class<T>, ?type:Dynamic):T {
var key:Dynamic = (type == null) ? 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) : []);
return instance; return instance;
} else { } else {
throw "Factory for\"" + i + "\" not found"; throw 'Factory for "${key}" not found';
} }
} }