@@ -8,6 +8,7 @@ import 'package:source_span/source_span.dart';
88
99import '../../../visitor/interface/expression.dart' ;
1010import '../expression.dart' ;
11+ import 'list.dart' ;
1112
1213/// A binary operator, as in `1 + 2` or `$this and $other` .
1314///
@@ -64,8 +65,11 @@ class BinaryOperationExpression implements Expression {
6465 var buffer = StringBuffer ();
6566
6667 var left = this .left; // Hack to make analysis work.
67- var leftNeedsParens = left is BinaryOperationExpression &&
68- left.operator .precedence < operator .precedence;
68+ var leftNeedsParens = (left is BinaryOperationExpression &&
69+ left.operator .precedence < operator .precedence) ||
70+ (left is ListExpression &&
71+ ! left.hasBrackets &&
72+ left.contents.length > 1 );
6973 if (leftNeedsParens) buffer.writeCharCode ($lparen);
7074 buffer.write (left);
7175 if (leftNeedsParens) buffer.writeCharCode ($rparen);
@@ -75,8 +79,12 @@ class BinaryOperationExpression implements Expression {
7579 buffer.writeCharCode ($space);
7680
7781 var right = this .right; // Hack to make analysis work.
78- var rightNeedsParens = right is BinaryOperationExpression &&
79- right.operator .precedence <= operator .precedence;
82+ var rightNeedsParens = (right is BinaryOperationExpression &&
83+ right.operator .precedence <= operator .precedence &&
84+ ! (right.operator == operator && operator .isAssociative)) ||
85+ (right is ListExpression &&
86+ ! right.hasBrackets &&
87+ right.contents.length > 1 );
8088 if (rightNeedsParens) buffer.writeCharCode ($lparen);
8189 buffer.write (right);
8290 if (rightNeedsParens) buffer.writeCharCode ($rparen);
@@ -93,10 +101,10 @@ enum BinaryOperator {
93101 singleEquals ('single equals' , '=' , 0 ),
94102
95103 /// The disjunction operator, `or` .
96- or ('or' , 'or' , 1 ),
104+ or ('or' , 'or' , 1 , associative : true ),
97105
98106 /// The conjunction operator, `and` .
99- and ('and' , 'and' , 2 ),
107+ and ('and' , 'and' , 2 , associative : true ),
100108
101109 /// The equality operator, `==` .
102110 equals ('equals' , '==' , 3 ),
@@ -117,13 +125,13 @@ enum BinaryOperator {
117125 lessThanOrEquals ('less than or equals' , '<=' , 4 ),
118126
119127 /// The addition operator, `+` .
120- plus ('plus' , '+' , 5 ),
128+ plus ('plus' , '+' , 5 , associative : true ),
121129
122130 /// The subtraction operator, `-` .
123131 minus ('minus' , '-' , 5 ),
124132
125133 /// The multiplication operator, `*` .
126- times ('times' , '*' , 6 ),
134+ times ('times' , '*' , 6 , associative : true ),
127135
128136 /// The division operator, `/` .
129137 dividedBy ('divided by' , '/' , 6 ),
@@ -142,7 +150,14 @@ enum BinaryOperator {
142150 /// An operator with higher precedence binds tighter.
143151 final int precedence;
144152
145- const BinaryOperator (this .name, this .operator , this .precedence);
153+ /// Whether this operation has the [associative property] .
154+ ///
155+ /// [associative property] : https://en.wikipedia.org/wiki/Associative_property
156+ final bool isAssociative;
157+
158+ const BinaryOperator (this .name, this .operator , this .precedence,
159+ {bool associative = false })
160+ : isAssociative = associative;
146161
147162 String toString () => name;
148163}
0 commit comments