From 910f8f0d6fa5ea1135ca7acdd1b4bfa2928ad623 Mon Sep 17 00:00:00 2001 From: Dima Granetchi Date: Mon, 17 Nov 2014 19:46:59 +0200 Subject: [PATCH 1/2] Bind extended work --- src/bindx/Bindx.hx | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/bindx/Bindx.hx diff --git a/src/bindx/Bindx.hx b/src/bindx/Bindx.hx new file mode 100644 index 0000000..c838950 --- /dev/null +++ b/src/bindx/Bindx.hx @@ -0,0 +1,48 @@ +package bindx; + +#if macro + +import bindx.Error; +import haxe.macro.Expr; + +#end +class Bindx { + + @:noUsing macro static public function bindChain(expr:Expr, listener:Expr):Expr { + return internalBindChain(expr, listener); + } + + #if macro + static function internalBindChain(expr:Expr, listener:Expr):Expr { + var prevField = Bind.checkField(expr); + var field = prevField; + var fields = []; + var rest:Expr; + while (field != null) { + try { + field = Bind.tryCheckField(prevField.expr); + fields.push(field.field); + rest = field.expr; + } + catch (e:FatalError) { + e.contextFatal(); + } + catch (e:Error) { + switch (prevField.expr) { + case EField(e, field): + var classType = Context.typeof(e).follow().getClass(); + var field:ClassField = classType.findField(field, null); + fields.push(field); + rest = e; + case EConst(CIdent(_)): + rest = prevField.expr; + case _: + rest = prevField.expr; + } + } + prevField = field; + } + } + #end + +} \ No newline at end of file From 42aabddec3703d69f3325f424645e509745eea9e Mon Sep 17 00:00:00 2001 From: Dima Granetchi Date: Tue, 18 Nov 2014 20:02:52 +0200 Subject: [PATCH 2/2] chain bind WIP --- src/bindx/Bind.hx | 25 +++++++----- src/bindx/Bindx.hx | 48 ----------------------- src/bindx/BindxExt.hx | 88 +++++++++++++++++++++++++++++++++++++++++++ test/ChainBindTest.hx | 55 +++++++++++++++++++++++++++ test/Tests.hx | 23 ++++++++++- 5 files changed, 180 insertions(+), 59 deletions(-) delete mode 100644 src/bindx/Bindx.hx create mode 100644 src/bindx/BindxExt.hx create mode 100644 test/ChainBindTest.hx diff --git a/src/bindx/Bind.hx b/src/bindx/Bind.hx index 0508ff0..82dd3df 100644 --- a/src/bindx/Bind.hx +++ b/src/bindx/Bind.hx @@ -64,10 +64,19 @@ class Bind { } public static function checkField(field:Expr):{e:Expr, field:ClassField} { - return try { tryCheckField(field); } catch (e:bindx.Error) { e.contextError(); null; }; + var res = null; + try { + res = tryCheckField(field); + if (res.error != null) + res.error.contextError(); + } catch (e:bindx.Error) { + e.contextError(); + }; + return res; } - public static function tryCheckField(field:Expr):{e:Expr, field:ClassField} { + public static function tryCheckField(field:Expr):{e:Expr, field:ClassField, error:bindx.Error} { + var error:bindx.Error; switch (field.expr) { case EField(e, field): var classType = Context.typeof(e).follow().getClass(); @@ -76,8 +85,7 @@ class Bind { return null; } if (!isBindable(classType)) { - throw new Error('\'${e.toString()}\' must be bindx.IBindable', e.pos); - return null; + error = new bindx.Error('\'${e.toString()}\' must be bindx.IBindable', e.pos); } var field:ClassField = classType.findField(field, null); @@ -87,17 +95,16 @@ class Bind { } if (!field.hasBindableMeta()) { - throw new Error('\'${e.toString()}.${field.name}\' is not bindable', field.pos); - return null; + error = new bindx.Error('\'${e.toString()}.${field.name}\' is not bindable', field.pos); } - return {e:e, field:field}; + return {e:e, field:field, error:error}; case EConst(CIdent(_)): - throw new Error('can\'t bind \'${field.toString()}\'. Please use \'this.${field.toString()}\'', field.pos); + return {e:field, field:null, error:new bindx.Error('can\'t bind \'${field.toString()}\'. Please use \'this.${field.toString()}\'', field.pos)}; case _: - throw new Error('can\'t bind field \'${field.toString()}\'', field.pos); + return {e:field, field:null, error:new bindx.Error('can\'t bind field \'${field.toString()}\'', field.pos)}; } return null; } diff --git a/src/bindx/Bindx.hx b/src/bindx/Bindx.hx deleted file mode 100644 index c838950..0000000 --- a/src/bindx/Bindx.hx +++ /dev/null @@ -1,48 +0,0 @@ -package bindx; - -#if macro - -import bindx.Error; -import haxe.macro.Expr; - -#end -class Bindx { - - @:noUsing macro static public function bindChain(expr:Expr, listener:Expr):Expr { - return internalBindChain(expr, listener); - } - - #if macro - static function internalBindChain(expr:Expr, listener:Expr):Expr { - var prevField = Bind.checkField(expr); - var field = prevField; - var fields = []; - var rest:Expr; - while (field != null) { - try { - field = Bind.tryCheckField(prevField.expr); - fields.push(field.field); - rest = field.expr; - } - catch (e:FatalError) { - e.contextFatal(); - } - catch (e:Error) { - switch (prevField.expr) { - case EField(e, field): - var classType = Context.typeof(e).follow().getClass(); - var field:ClassField = classType.findField(field, null); - fields.push(field); - rest = e; - case EConst(CIdent(_)): - rest = prevField.expr; - case _: - rest = prevField.expr; - } - } - prevField = field; - } - } - #end - -} \ No newline at end of file diff --git a/src/bindx/BindxExt.hx b/src/bindx/BindxExt.hx new file mode 100644 index 0000000..27cc3fa --- /dev/null +++ b/src/bindx/BindxExt.hx @@ -0,0 +1,88 @@ +package bindx; + +#if macro + + +import bindx.Error; +import haxe.macro.Expr; +import haxe.macro.Type; + +using Lambda; + +typedef FieldExpr = { + var field:ClassField; + var bindable:Bool; + var e:Expr; + @:optional var params:Array; +} + +#end +@:access(bindx.BindMacros) +class BindExt { + + @:noUsing macro static public function chain(expr:Expr, listener:Expr):Expr { + return internalBindChain(expr, listener); + } + + #if macro + static function internalBindChain(expr:Expr, listener:Expr):Expr { + var printer = new haxe.macro.Printer(); + var first = Bind.checkField(expr); + var prevField = {e:first.e, field:first.field, error:null}; + var fields:Array = [{field:first.field, bindable:true, e:first.e}]; + while (true) { + var field = null; + try { + field = Bind.tryCheckField(prevField.e); + if (field.field != null) + fields.unshift({field:field.field, bindable:field.error == null, e:field.e}); + else if (field.error != null) { + var end = true; + switch (prevField.e.expr) { + case ECall(e, params): + field = Bind.tryCheckField(e); + fields.unshift({e:field.e, field:field.field, params:params, bindable:field.error == null}); + end = false; + case _: + } + if (end) break; + } + } + catch (e:FatalError) { + e.contextFatal(); + } + prevField = field; + } + fields.iter(function (it) trace(printer.printExpr(it.e) + " -> " + it.field.name + (it.params != null ? '(${printer.printExprs(it.params, ",")})' : "") + " bind:" + it.bindable)); + var i = 0; + + + var res = []; + for (field in fields) { + var listenerName = 'listener$i'; + if (field.bindable) { + var listener = switch (field.field.kind) { + case FVar(_, _): + macro function (from, to) { + $listener($a{[from, to]}); + } + case FMethod(_): + macro function() { + + } + } + res.push(macro var $listenerName = $listener); + var expr = BindMacros.bindingSignalProvider.getClassFieldBindExpr(field.e, field.field, listener = macro $i{listenerName}); + trace(printer.printExpr(expr)); + } + else { + trace(printer.printExpr(field.e) + " . " + field.field.name); + } + i++; + } + + return macro {}; + } + #end + +} \ No newline at end of file diff --git a/test/ChainBindTest.hx b/test/ChainBindTest.hx new file mode 100644 index 0000000..2ce01cb --- /dev/null +++ b/test/ChainBindTest.hx @@ -0,0 +1,55 @@ +package ; + +import bindx.Bind; +import bindx.BindxExt; +import bindx.IBindable; +import buddy.BuddySuite; + +using buddy.Should; + +//@exclude +class ChainBindTest extends BuddySuite { + + public function new() { + + describe("Using BindExt.chain", { + + var b:BindableChain; + var callNum:Int; + + before({ + b = new BindableChain(); + b.c = new BindableChain(); + callNum = 0; + }); + + it("BindExt.chain should bind chain changes", { + b.c.f("tada").d = "a"; + BindExt.chain(b.c.f("tada").d, function (_, _) callNum++); + + b.c.f("tada").d = "b"; + callNum.should.be(1); + }); + + }); + } +} + + +class BindableChain implements bindx.IBindable { + + @:bindable + public var d:String; + + public var nd:String; + + public var c:BindableChain; + + @:bindable + public function f(s:String):BindableChain { + return c; + } + + public function new() { + } +} \ No newline at end of file diff --git a/test/Tests.hx b/test/Tests.hx index 2fea814..42c6157 100644 --- a/test/Tests.hx +++ b/test/Tests.hx @@ -1,6 +1,25 @@ package ; import buddy.BuddySuite; +import buddy.SuitesRunner; -@:build(buddy.GenerateMain.build(null, ["test"])) -class Tests extends BuddySuite {} \ No newline at end of file +class Tests extends BuddySuite { + + public static function main() { + var reporter = new buddy.reporting.TravisHxReporter(); + + var runner = new SuitesRunner([ + new BaseTest(), + new InheritanceTest(), + new InlineTest(), + new MetaTest(), + new SignalTest(), + new TestProperty(), + // new ChainBindTest(), + ], reporter); + + runner.run(); + + return runner.statusCode(); + } +} \ No newline at end of file