feat(Parser): associate pipes right to left

closes #4605

BREAKING CHANGE:

Before:

`1 + 1 | pipe:a | pipe:b` was parsed as `(1 + 1) | pipe:(a | pipe:b)`

After:

`1 + 1 | pipe:a | pipe:b` is parsed as `((1 + 1) | pipe:a) | pipe:b`

Closes #4716
This commit is contained in:
Victor Berchet 2015-10-13 18:55:46 -07:00
parent 77604b8b18
commit 4639f449cf
4 changed files with 20 additions and 19 deletions

View File

@ -216,6 +216,14 @@ export class _ParseAST {
return n.toString(); return n.toString();
} }
parseSimpleBinding(): AST {
var ast = this.parseChain();
if (!SimpleExpressionChecker.check(ast)) {
this.error(`Simple binding expression can only contain field access and constants'`);
}
return ast;
}
parseChain(): AST { parseChain(): AST {
var exprs = []; var exprs = [];
while (this.index < this.tokens.length) { while (this.index < this.tokens.length) {
@ -237,14 +245,6 @@ export class _ParseAST {
return new Chain(exprs); return new Chain(exprs);
} }
parseSimpleBinding(): AST {
var ast = this.parseChain();
if (!SimpleExpressionChecker.check(ast)) {
this.error(`Simple binding expression can only contain field access and constants'`);
}
return ast;
}
parsePipe(): AST { parsePipe(): AST {
var result = this.parseExpression(); var result = this.parseExpression();
if (this.optionalOperator("|")) { if (this.optionalOperator("|")) {
@ -256,7 +256,7 @@ export class _ParseAST {
var name = this.expectIdentifierOrKeyword(); var name = this.expectIdentifierOrKeyword();
var args = []; var args = [];
while (this.optionalCharacter($COLON)) { while (this.optionalCharacter($COLON)) {
args.push(this.parsePipe()); args.push(this.parseExpression());
} }
result = new BindingPipe(result, name, args); result = new BindingPipe(result, name, args);
} while (this.optionalOperator("|")); } while (this.optionalOperator("|"));

View File

@ -408,6 +408,7 @@ var _availableDefinitions = [
'name | pipe', 'name | pipe',
'(name | pipe).length', '(name | pipe).length',
"name | pipe:'one':address.city", "name | pipe:'one':address.city",
"name | pipe:'a':'b' | pipe:0:1:2",
'value', 'value',
'a', 'a',
'address.city', 'address.city',

View File

@ -354,6 +354,14 @@ export function main() {
expect(val.dispatcher.loggedValues).toEqual(['value one two default']); expect(val.dispatcher.loggedValues).toEqual(['value one two default']);
}); });
it('should associate pipes right-to-left', () => {
var registry = new FakePipes('pipe', () => new MultiArgPipe());
var person = new Person('value');
var val = _createChangeDetector("name | pipe:'a':'b' | pipe:0:1:2", person, registry);
val.changeDetector.detectChanges();
expect(val.dispatcher.loggedValues).toEqual(['value a b default 0 1 2']);
});
it('should not reevaluate pure pipes unless its context or arg changes', () => { it('should not reevaluate pure pipes unless its context or arg changes', () => {
var pipe = new CountingPipe(); var pipe = new CountingPipe();
var registry = new FakePipes('pipe', () => pipe, {pure: true}); var registry = new FakePipes('pipe', () => pipe, {pure: true});

View File

@ -6,14 +6,6 @@ import {Unparser} from './unparser';
import {Lexer} from 'angular2/src/core/change_detection/parser/lexer'; import {Lexer} from 'angular2/src/core/change_detection/parser/lexer';
import {BindingPipe, LiteralPrimitive, AST} from 'angular2/src/core/change_detection/parser/ast'; import {BindingPipe, LiteralPrimitive, AST} from 'angular2/src/core/change_detection/parser/ast';
class TestData {
constructor(public a?: any, public b?: any, public fnReturnValue?: any) {}
fn() { return this.fnReturnValue; }
add(a, b) { return a + b; }
}
export function main() { export function main() {
function createParser() { return new Parser(new Lexer(), reflector); } function createParser() { return new Parser(new Lexer(), reflector); }
@ -229,8 +221,8 @@ export function main() {
checkBinding('a[b] | c', '(a[b] | c)'); checkBinding('a[b] | c', '(a[b] | c)');
checkBinding('a?.b | c', '(a?.b | c)'); checkBinding('a?.b | c', '(a?.b | c)');
checkBinding('true | a', '(true | a)'); checkBinding('true | a', '(true | a)');
checkBinding('a | b:c | d', '(a | b:(c | d))'); checkBinding('a | b:c | d', '((a | b:c) | d)');
checkBinding('(a | b:c) | d', '((a | b:c) | d)'); checkBinding('a | b:(c | d)', '(a | b:(c | d))');
}); });
it('should only allow identifier or keyword as formatter names', () => { it('should only allow identifier or keyword as formatter names', () => {