| // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | import "package:expect/expect.dart"; | 
 |  | 
 | class A { | 
 |   int value; | 
 |   A(this.value); | 
 |   void set(int value) { | 
 |     this.value = value; | 
 |   } | 
 |  | 
 |   int get() => value; | 
 |   int operator [](int index) => value + index; | 
 |   void operator []=(int index, int newValue) { | 
 |     value += -index + newValue; | 
 |   } | 
 |  | 
 |   void test(int expected) { | 
 |     Expect.equals(expected, value); | 
 |   } | 
 |  | 
 |   Function limp(int n) { | 
 |     if (n == 0) return set; | 
 |     return () => limp(n - 1); | 
 |   } | 
 |  | 
 |   A get self => this; | 
 |   A operator +(A other) { | 
 |     this.value += other.value; | 
 |     return this; | 
 |   } | 
 | } | 
 |  | 
 | class Box { | 
 |   A value; | 
 |   Box(this.value); | 
 |   A operator [](int pos) => value; | 
 |   void operator []=(int pos, A a) { | 
 |     value = a; | 
 |   } | 
 |  | 
 |   A get x => value; | 
 |   void set x(A a) { | 
 |     value = a; | 
 |   } | 
 | } | 
 |  | 
 | // Subset of grammar being tested. | 
 | // | 
 | // expression: | 
 | //       assignableExpression assignmentOperator expression | 
 | //     | conditionalExpression cascadeSection* | 
 | //     ; | 
 | // expressionWithoutCascade: | 
 | //       assignableExpression assignmentOperator expressionWithoutCascade | 
 | //     | conditionalExpression | 
 | //     ; | 
 | // expressionList: | 
 | //       expression (',' expression)* | 
 | //     ; | 
 | // assignableExpression: | 
 | //       primary (arguments* assignableSelector)+ | 
 | //     | super assignableSelector | 
 | //     | identifier | 
 | //     ; | 
 | // conditionalExpression: | 
 | //     logicalOrExpression ('?' expressionWithoutCascade ':' expressionWithoutCascade)? | 
 | //     ; | 
 | // primary: | 
 | //       thisExpression | 
 | //     | super assignableSelector | 
 | //     | functionExpression | 
 | //     | literal | 
 | //     | identifier | 
 | //     | newExpression | 
 | //     | constObjectExpression | 
 | //     | '(' expression ')' | 
 | //     ; | 
 | // assignableSelector: | 
 | //       '[' expression ']' | 
 | //     | '.' identifier | 
 | //     ; | 
 | // | 
 | // In words: | 
 | //  An assignableExpression is either a variable or something ending in | 
 | //  [expression] or .identifier. | 
 |  | 
 | main() { | 
 |   A a = new A(42); | 
 |   A original = a; | 
 |   A b = new A(87); | 
 |   fa() => a; | 
 |   Box box = new Box(a); | 
 |   // Different expressions on the left-hand side of '..'. | 
 |   //  conditionalExpression >> postfixExpression > primary selector* | 
 |   Expect.equals( | 
 |     a, | 
 |     a | 
 |       ..set(37) | 
 |       ..get(), | 
 |   ); | 
 |   a.test(37); | 
 |   Expect.equals( | 
 |     a, | 
 |     fa() | 
 |       ..set(42) | 
 |       ..get(), | 
 |   ); | 
 |   a.test(42); | 
 |   Expect.equals( | 
 |     a, | 
 |     box.x | 
 |       ..set(37) | 
 |       ..get(), | 
 |   ); | 
 |   a.test(37); | 
 |   // '..' binds to 'b + a', i.e., to the 'b' object, not to 'a'. | 
 |   Expect.equals( | 
 |     b, | 
 |     b + a | 
 |       ..test(124) | 
 |       ..set(117) | 
 |       ..get(), | 
 |   ); | 
 |   b.test(117); | 
 |   a.test(37); | 
 |  | 
 |   // expression :: conditionalExpression cascadeSection | 
 |   // and conditionalExpression ends in expressionWithoutCascade. | 
 |   // I.e., '..' binds to the entire condition expression, not to 'b'. | 
 |   (a.value == 37) ? a : b | 
 |     ..set(42); | 
 |   a.test(42); | 
 |  | 
 |   // This binds .. to 'a', not 'c=a', and performs assignment after reading | 
 |   // c.get(). | 
 |   A c = new A(21); | 
 |   c = a..set(c.get()); // FAILING. | 
 |   Expect.equals(a, c); | 
 |   Expect.equals(original, a); | 
 |   a.test(21); // Fails as 42 if above is parsed as (c = a)..set(c.get()). | 
 |  | 
 |   // Should be parsed as (box..x = (c = a))..x.test(21). | 
 |   c = A(-1); | 
 |   box | 
 |     ..x = c = a | 
 |     ..x.test(21); | 
 |   c.test(21); | 
 |   // Other variants | 
 |   c = A(-1); | 
 |   box | 
 |     ..x = c = (a..test(21)) | 
 |     ..x.test(21); | 
 |   c.test(21); | 
 |  | 
 |   c = A(-1); | 
 |   box | 
 |     ..x = (c = a..test(21)) | 
 |     ..x.test(21); | 
 |   c.test(21); | 
 |  | 
 |   // Should work the same: | 
 |   (a..set(42))..test(42); | 
 |   a | 
 |     ..set(21) | 
 |     ..test(21); | 
 |  | 
 |   c = A(-1); | 
 |   Box originalBox = box; | 
 |   // Should parse as: | 
 |   // box = (box..x = (a.value == 21 ? b : c)..x.test(117)); | 
 |   box = | 
 |       box | 
 |         ..x = a.value == 21 ? b : c | 
 |         ..x.test(117); | 
 |   Expect.equals(originalBox, box); | 
 |   Expect.equals(box.value, b); | 
 |  | 
 |   // New cascades are allowed inside an expressionWithoutCascade if properly | 
 |   // delimited. | 
 |   box | 
 |     ..x = | 
 |         (a | 
 |           ..set(42) | 
 |           ..test(42)) | 
 |     ..x.test(42); | 
 | } |