| Index: frog/tests/leg_only/src/CascadePrecedenceTest.dart
|
| diff --git a/frog/tests/leg_only/src/CascadePrecedenceTest.dart b/frog/tests/leg_only/src/CascadePrecedenceTest.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2ed263e0e4a291c6578e1a055e6ce1c7af3b5462
|
| --- /dev/null
|
| +++ b/frog/tests/leg_only/src/CascadePrecedenceTest.dart
|
| @@ -0,0 +1,137 @@
|
| +// 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.
|
| +
|
| +
|
| +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);
|
| +}
|
|
|