bind complex exprs (prevent double bind)
This commit is contained in:
+1
-1
@@ -114,7 +114,7 @@ class Bind {
|
|||||||
|
|
||||||
case _:
|
case _:
|
||||||
}
|
}
|
||||||
return {e:f, field:null, error:new bindx.Error('Can\'t bind field \'${f.toString()}\'', f.pos)};
|
return {e:f, field:null, error:new bindx.Error('Can\'t bind \'${f.toString()}\'', f.pos)};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isBindable(classType:ClassType):Bool {
|
public static function isBindable(classType:ClassType):Bool {
|
||||||
|
|||||||
+45
-15
@@ -22,6 +22,7 @@ typedef Chain = {
|
|||||||
var init:Array<Expr>;
|
var init:Array<Expr>;
|
||||||
var bind:Array<Expr>;
|
var bind:Array<Expr>;
|
||||||
var unbind:Array<Expr>;
|
var unbind:Array<Expr>;
|
||||||
|
var expr:Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#end
|
#end
|
||||||
@@ -57,10 +58,12 @@ class BindExt {
|
|||||||
var fieldListenerNameExpr = macro $i{fieldListenerName};
|
var fieldListenerNameExpr = macro $i{fieldListenerName};
|
||||||
var methodListenerName = "methodListener";
|
var methodListenerName = "methodListener";
|
||||||
var methodListenerNameExpr = macro $i{methodListenerName};
|
var methodListenerNameExpr = macro $i{methodListenerName};
|
||||||
var chain:Chain = { init:[], bind:[], unbind:[] };
|
var chain:Chain = { init:[], bind:[], unbind:[], expr:expr };
|
||||||
|
var binded:Map<String, Bool> = new Map();
|
||||||
|
|
||||||
var prefix = 0;
|
var prefix = 0;
|
||||||
function findChain(expr:Expr) {
|
function findChain(expr:Expr) {
|
||||||
|
//trace(new Printer().printExpr(expr));
|
||||||
var ch = [];
|
var ch = [];
|
||||||
var isChain;
|
var isChain;
|
||||||
var e = expr;
|
var e = expr;
|
||||||
@@ -84,14 +87,20 @@ class BindExt {
|
|||||||
if (e != start) {
|
if (e != start) {
|
||||||
var pre = '_${prefix++}';
|
var pre = '_${prefix++}';
|
||||||
var zeroListener = listenerName(0, pre);
|
var zeroListener = listenerName(0, pre);
|
||||||
|
|
||||||
var c = null;
|
var c = null;
|
||||||
try { c = warnPrepareChain(start, macro $i{zeroListener}, pre); } catch (e:bindx.Error) { e.contextWarning(); }
|
try { c = warnPrepareChain(start, macro $i{zeroListener}, pre, true); } catch (e:bindx.Error) { e.contextWarning(); }
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
chain.init.push(macro var $zeroListener = ${ecall ? methodListenerNameExpr : fieldListenerNameExpr});
|
var key = c.expr.toString();
|
||||||
chain.init = chain.init.concat(c.init);
|
if (!binded.exists(key)) {
|
||||||
chain.bind = chain.bind.concat(c.bind);
|
binded.set(key, true);
|
||||||
chain.unbind = chain.unbind.concat(c.unbind);
|
Context.warning('Bind ${start.toString()}', start.pos);
|
||||||
|
chain.bind.unshift(macro var $zeroListener = ${ecall ? methodListenerNameExpr : fieldListenerNameExpr});
|
||||||
|
chain.init = chain.init.concat(c.init);
|
||||||
|
chain.bind = chain.bind.concat(c.bind);
|
||||||
|
chain.unbind = chain.unbind.concat(c.unbind);
|
||||||
|
} else {
|
||||||
|
Context.warning("skip second bind " + c.expr.toString(), start.pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.iter(findChain);
|
e.iter(findChain);
|
||||||
@@ -120,11 +129,13 @@ class BindExt {
|
|||||||
|
|
||||||
static function checkFields(expr:Expr):Array<FieldExpr> {
|
static function checkFields(expr:Expr):Array<FieldExpr> {
|
||||||
var first = Bind.checkField(expr);
|
var first = Bind.checkField(expr);
|
||||||
if (first.field == null || first.error != null)
|
if (first.field == null) {
|
||||||
throw new FatalError('${expr.toString()} is not bindable', expr.pos);
|
if (first.error != null) throw first.error;
|
||||||
|
else throw new FatalError('${expr.toString()} is not bindable.', expr.pos);
|
||||||
|
}
|
||||||
|
|
||||||
var prevField = {e:first.e, field:first.field, error:null};
|
var prevField = {e:first.e, field:first.field, error:null};
|
||||||
var fields:Array<FieldExpr> = [ { field:first.field, bindable:true, e:first.e } ];
|
var fields:Array<FieldExpr> = [ { field:first.field, bindable:first.error == null, e:first.e } ];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var field = Bind.checkField(prevField.e);
|
var field = Bind.checkField(prevField.e);
|
||||||
@@ -143,15 +154,16 @@ class BindExt {
|
|||||||
if (end) break;
|
if (end) break;
|
||||||
}
|
}
|
||||||
else if (field.e == null) {
|
else if (field.e == null) {
|
||||||
throw new FatalError('${prevField.e.toString()} is not bindable.', expr.pos);
|
throw new FatalError('${prevField.e.toString()} is not bindable.', prevField.e.pos);
|
||||||
}
|
}
|
||||||
prevField = field;
|
prevField = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//trace(expr.toString() + " " + [for (f in fields) f.bindable]);
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function warnPrepareChain(expr:Expr, listener:Expr, prefix = ""):Chain {
|
static function warnPrepareChain(expr:Expr, listener:Expr, prefix = "", skipUnbindable = false):Chain {
|
||||||
var fields = checkFields(expr);
|
var fields = checkFields(expr);
|
||||||
|
|
||||||
if (fields.length == 0) {
|
if (fields.length == 0) {
|
||||||
@@ -164,7 +176,13 @@ class BindExt {
|
|||||||
while (i-- > 0) {
|
while (i-- > 0) {
|
||||||
var f = fields[i];
|
var f = fields[i];
|
||||||
if (first != null) f.bindable = false;
|
if (first != null) f.bindable = false;
|
||||||
else if (!f.bindable && first == null) first = f;
|
else if (!f.bindable && first == null) {
|
||||||
|
first = f;
|
||||||
|
if (skipUnbindable) {
|
||||||
|
fields = fields.splice(i+1, fields.length - i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var bindableNum = fields.fold(function (it, n) return n += it.bindable ? 1 : 0, 0);
|
var bindableNum = fields.fold(function (it, n) return n += it.bindable ? 1 : 0, 0);
|
||||||
if (bindableNum == 0) {
|
if (bindableNum == 0) {
|
||||||
@@ -181,11 +199,15 @@ class BindExt {
|
|||||||
inline static function listenerName(idx:Int, prefix) return '${prefix}listener$idx';
|
inline static function listenerName(idx:Int, prefix) return '${prefix}listener$idx';
|
||||||
|
|
||||||
static function prepareChain(fields:Array<FieldExpr>, listener:Expr, pos:Position, prefix = ""):Chain {
|
static function prepareChain(fields:Array<FieldExpr>, listener:Expr, pos:Position, prefix = ""):Chain {
|
||||||
var res:Chain = { init:[], bind:[], unbind:[] };
|
var res:Chain = { init:[], bind:[], unbind:[], expr:null };
|
||||||
|
|
||||||
var prevListenerName = listenerName(0, prefix);
|
var prevListenerName = listenerName(0, prefix);
|
||||||
var prevListenerNameExpr = macro $i { prevListenerName };
|
var prevListenerNameExpr = macro $i { prevListenerName };
|
||||||
var zeroListener = fields[0].bindable ? { f:fields[0], l:prevListenerNameExpr } : null;
|
var zeroListener = fields[0].bindable ? { f:fields[0], l:prevListenerNameExpr } : null;
|
||||||
|
if (zeroListener != null) {
|
||||||
|
var fn = zeroListener.f.field.name;
|
||||||
|
res.expr = macro ${zeroListener.f.e}.$fn;
|
||||||
|
}
|
||||||
var i = -1;
|
var i = -1;
|
||||||
while (++i < fields.length - 1) {
|
while (++i < fields.length - 1) {
|
||||||
var field = fields[i + 1];
|
var field = fields[i + 1];
|
||||||
@@ -201,7 +223,14 @@ class BindExt {
|
|||||||
|
|
||||||
var fieldListenerBody = [];
|
var fieldListenerBody = [];
|
||||||
var fieldListener;
|
var fieldListener;
|
||||||
if (field.bindable) zeroListener = { f:field, l:listenerNameExpr };
|
if (field.bindable) {
|
||||||
|
zeroListener = { f:field, l:listenerNameExpr };
|
||||||
|
|
||||||
|
}
|
||||||
|
if (prev.bindable && res.expr == null) {
|
||||||
|
var fn = prev.field.name;
|
||||||
|
res.expr = macro ${prev.e}.$fn;
|
||||||
|
}
|
||||||
|
|
||||||
var type = Context.typeof(field.e).toComplexType();
|
var type = Context.typeof(field.e).toComplexType();
|
||||||
|
|
||||||
@@ -243,6 +272,7 @@ class BindExt {
|
|||||||
if (zeroListener == null || zeroListener.f.bindable == false)
|
if (zeroListener == null || zeroListener.f.bindable == false)
|
||||||
throw new bindx.Error("Chain is not bindable.", pos);
|
throw new bindx.Error("Chain is not bindable.", pos);
|
||||||
|
|
||||||
|
//trace(zeroListener.f);
|
||||||
res.init.push(BindMacros.bindingSignalProvider.getClassFieldBindExpr(zeroListener.f.e, zeroListener.f.field, zeroListener.l ));
|
res.init.push(BindMacros.bindingSignalProvider.getClassFieldBindExpr(zeroListener.f.e, zeroListener.f.field, zeroListener.l ));
|
||||||
res.unbind.push(BindMacros.bindingSignalProvider.getClassFieldUnbindExpr(zeroListener.f.e, zeroListener.f.field, zeroListener.l ));
|
res.unbind.push(BindMacros.bindingSignalProvider.getClassFieldUnbindExpr(zeroListener.f.e, zeroListener.f.field, zeroListener.l ));
|
||||||
|
|
||||||
|
|||||||
+35
-2
@@ -24,9 +24,9 @@ class ExprBindTest extends BuddySuite {
|
|||||||
var b = new BaseTest.Bindable1();
|
var b = new BaseTest.Bindable1();
|
||||||
a.str = "a1";
|
a.str = "a1";
|
||||||
b.str = "b1";
|
b.str = "b1";
|
||||||
inline function val() return a.str + b.str + a.str.charAt(0) + "ab".charAt(0) + Std.string(1);
|
inline function val() return b.str + "ab".charAt(a.str.length - 2) + Std.string(1);
|
||||||
|
|
||||||
BindExt.expr(a.str + b.str + a.str.charAt(0) + "ab".charAt(0) + Std.string(1), function (from, to:String) {
|
BindExt.expr(b.str + "ab".charAt(a.str.length - 2) + Std.string(1), function (from, to:String) {
|
||||||
to.should.be(val());
|
to.should.be(val());
|
||||||
callNum ++;
|
callNum ++;
|
||||||
});
|
});
|
||||||
@@ -42,6 +42,39 @@ class ExprBindTest extends BuddySuite {
|
|||||||
callNum.should.be(3);
|
callNum.should.be(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("BindExt.chain should bind complex expresions", {
|
||||||
|
var a = new BaseTest.Bindable1();
|
||||||
|
var b = new BaseTest.Bindable1();
|
||||||
|
var c = new BaseTest.Bindable1();
|
||||||
|
a.str = "a1";
|
||||||
|
b.str = "";
|
||||||
|
c.str = "1";
|
||||||
|
inline function val() return if (a.str.charAt(b.str.length) == c.str) a.str else c.str;
|
||||||
|
|
||||||
|
BindExt.expr(if (a.str.charAt(b.str.length) == c.str) a.str else c.str, function (from, to:String) {
|
||||||
|
to.should.be(val());
|
||||||
|
callNum ++;
|
||||||
|
});
|
||||||
|
|
||||||
|
callNum.should.be(1);
|
||||||
|
|
||||||
|
b.str = "1";
|
||||||
|
|
||||||
|
callNum.should.be(2);
|
||||||
|
|
||||||
|
b.str = "";
|
||||||
|
|
||||||
|
callNum.should.be(3);
|
||||||
|
|
||||||
|
a.str = "b2";
|
||||||
|
|
||||||
|
callNum.should.be(4);
|
||||||
|
|
||||||
|
c.str = "b";
|
||||||
|
|
||||||
|
callNum.should.be(5);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user