|  | // 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 = null; | 
|  | box | 
|  | ..x = c = a | 
|  | ..x.test(21); | 
|  | c.test(21); | 
|  | // Other variants | 
|  | c = null; | 
|  | box | 
|  | ..x = c = (a..test(21)) | 
|  | ..x.test(21); | 
|  | c.test(21); | 
|  |  | 
|  | c = null; | 
|  | 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 = null; | 
|  | 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); | 
|  | } |