Files
haxework/haxework/gui/build/Builder.hx
2015-07-13 14:13:38 +03:00

181 lines
5.4 KiB
Haxe
Executable File

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.loadFile(templateFile);
if (templateKey != null) template = Reflect.field(template, templateKey);
if (templateMeta[1] != null) {
styleFile = Context.resolvePath(templateMeta[1]);
style = BuilderUtil.loadFile(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;
return Context.makePosition({min:min, max:max, file:templateFile});
}
private function specialValue(name:String, key:String, a:Array<String>):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()));
//res + ".get(\"" + a[2] + "\")";
null;
case "locale":
"new haxework.locale.LString(\"" + a[1] + "\")";
case "class":
a[1];
case "layout":
var template = BuilderUtil.loadFile(a[1]);
return getValue(name, key, template);
case "link":
"(links == null) ? untyped this : Reflect.field(links, \"" + a[1] + "\")";
case _:
throw "Unsupported prefix \"" + a[0] + "\"";
}
}
private function getValue(name:String, key:String, value:Dynamic):Dynamic {
return if (Std.is(value, Array)) {
value.map(function(v) { return getValue(null, null, v); });
} else if (Std.is(value, String)) {
if (value.charAt(0) == "@") {
specialValue(name, key, value.substring(1, value.length).split(":"));
} 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");
exprs.push(Context.parse("var " + n + " = new " + type + "()", getPosition()));
createElement(value, n);
n;
} else {
value;
}
} 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 (!Reflect.hasField(template, 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 type = switch (expr.expr) {
case EVars(vars): vars[0].type;
case _: null;
}
fields.push({
name: id,
access: [APublic],
pos: getPosition(),
kind: FProp("default", "null", type)
});
exprs.push(Context.parse("this." + id + " = " + name, getPosition()));
}
for (key in Reflect.fields(template)) {
if (key.charAt(0) == "$" || ["type", "style"].indexOf(key) > -1) continue;
var position = Reflect.field(template, "$" + key);
var value = getValue(name, key, Reflect.field(template, key));
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