blob: bf2d2f1a0629b05ba55adce88131c54da4776685 [file] [log] [blame]
// 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.
// @dart = 2.9
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);
}