From e1ecc34edd19b95d51fbcb1351b04b9876c974c1 Mon Sep 17 00:00:00 2001 From: Dhruv Manek Date: Fri, 30 Sep 2011 16:55:01 -0700 Subject: [PATCH] fix(parser): Fix short circuit of logical AND and OR operators Closes #433 --- src/parser.js | 38 +++++++++++++++++++------------------- test/ParserSpec.js | 22 +++++++++++++++++++--- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/parser.js b/src/parser.js index 5129f2f7ffad..f8978a0b3a89 100644 --- a/src/parser.js +++ b/src/parser.js @@ -5,25 +5,25 @@ var OPERATORS = { 'true':function(self){return true;}, 'false':function(self){return false;}, $undefined:noop, - '+':function(self, a,b){return (isDefined(a)?a:0)+(isDefined(b)?b:0);}, - '-':function(self, a,b){return (isDefined(a)?a:0)-(isDefined(b)?b:0);}, - '*':function(self, a,b){return a*b;}, - '/':function(self, a,b){return a/b;}, - '%':function(self, a,b){return a%b;}, - '^':function(self, a,b){return a^b;}, + '+':function(self, a,b){a=a(self); b=b(self); return (isDefined(a)?a:0)+(isDefined(b)?b:0);}, + '-':function(self, a,b){a=a(self); b=b(self); return (isDefined(a)?a:0)-(isDefined(b)?b:0);}, + '*':function(self, a,b){return a(self)*b(self);}, + '/':function(self, a,b){return a(self)/b(self);}, + '%':function(self, a,b){return a(self)%b(self);}, + '^':function(self, a,b){return a(self)^b(self);}, '=':noop, - '==':function(self, a,b){return a==b;}, - '!=':function(self, a,b){return a!=b;}, - '<':function(self, a,b){return a':function(self, a,b){return a>b;}, - '<=':function(self, a,b){return a<=b;}, - '>=':function(self, a,b){return a>=b;}, - '&&':function(self, a,b){return a&&b;}, - '||':function(self, a,b){return a||b;}, - '&':function(self, a,b){return a&b;}, + '==':function(self, a,b){return a(self)==b(self);}, + '!=':function(self, a,b){return a(self)!=b(self);}, + '<':function(self, a,b){return a(self)':function(self, a,b){return a(self)>b(self);}, + '<=':function(self, a,b){return a(self)<=b(self);}, + '>=':function(self, a,b){return a(self)>=b(self);}, + '&&':function(self, a,b){return a(self)&&b(self);}, + '||':function(self, a,b){return a(self)||b(self);}, + '&':function(self, a,b){return a(self)&b(self);}, // '|':function(self, a,b){return a|b;}, - '|':function(self, a,b){return b(self, a);}, - '!':function(self, a){return !a;} + '|':function(self, a,b){return b(self)(self, a(self));}, + '!':function(self, a){return !a(self);} }; var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; @@ -308,13 +308,13 @@ function parser(text, json){ function unaryFn(fn, right) { return function(self) { - return fn(self, right(self)); + return fn(self, right); }; } function binaryFn(left, fn, right) { return function(self) { - return fn(self, left(self), right(self)); + return fn(self, left, right); }; } diff --git a/test/ParserSpec.js b/test/ParserSpec.js index 4c3cb64b41e4..a5e1901c3948 100644 --- a/test/ParserSpec.js +++ b/test/ParserSpec.js @@ -391,7 +391,7 @@ describe('parser', function() { expect(scope.a).not.toBeDefined(); }); - it('should allow assignment after array dereference', function(){ + it('should allow assignment after array dereference', function() { scope = angular.scope(); scope.obj = [{}]; scope.$eval('obj[0].name=1'); @@ -399,14 +399,30 @@ describe('parser', function() { expect(scope.obj[0].name).toEqual(1); }); - describe('formatter', function(){ + it('should short-circuit AND operator', function() { + var scope = angular.scope(); + scope.run = function() { + throw "IT SHOULD NOT HAVE RUN"; + }; + expect(scope.$eval('false && run()')).toBe(false); + }); + + it('should short-circuit OR operator', function() { + var scope = angular.scope(); + scope.run = function() { + throw "IT SHOULD NOT HAVE RUN"; + }; + expect(scope.$eval('true || run()')).toBe(true); + }); + + describe('formatter', function() { it('should return no argument function', function() { var noop = parser('noop').formatter()(); expect(noop.format(null, 'abc')).toEqual('abc'); expect(noop.parse(null, '123')).toEqual('123'); }); - it('should delegate arguments', function(){ + it('should delegate arguments', function() { angularFormatter.myArgs = { parse: function(a, b){ return [a, b]; }, format: function(a, b){ return [a, b]; }