OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 interface Operation { | |
6 | |
7 } | |
8 | |
9 interface UnaryOperation extends Operation { | |
10 /** Returns [:null:] if it was unable to fold the operation. */ | |
11 Constant fold(Constant constant); | |
12 } | |
13 | |
14 class BitNotOperation implements UnaryOperation { | |
15 const BitNotOperation(); | |
16 Constant fold(Constant constant) { | |
17 if (constant.isInt()) { | |
18 IntConstant intConstant = constant; | |
19 return new IntConstant(~intConstant.value); | |
20 } | |
21 return null; | |
22 } | |
23 } | |
24 | |
25 class NegateOperation implements UnaryOperation { | |
26 const NegateOperation(); | |
27 Constant fold(Constant constant) { | |
28 if (constant.isInt()) { | |
29 IntConstant intConstant = constant; | |
30 return new IntConstant(-intConstant.value); | |
31 } | |
32 if (constant.isDouble()) { | |
33 DoubleConstant doubleConstant = constant; | |
34 return new DoubleConstant(-doubleConstant.value); | |
35 } | |
36 return null; | |
37 } | |
38 } | |
39 | |
40 class NotOperation implements UnaryOperation { | |
41 const NotOperation(); | |
42 Constant fold(Constant constant) { | |
43 if (constant.isBool()) { | |
44 BoolConstant boolConstant = constant; | |
45 return boolConstant.negate(); | |
46 } | |
47 return null; | |
48 } | |
49 } | |
50 | |
51 interface BinaryOperation extends Operation { | |
52 /** Returns [:null:] if it was unable to fold the operation. */ | |
53 Constant fold(Constant left, Constant right); | |
54 } | |
55 | |
56 /** | |
57 * Operations that only work if both arguments are integers. | |
58 */ | |
59 class BinaryIntOperation implements BinaryOperation { | |
60 const BinaryIntOperation(); | |
61 Constant fold(Constant left, Constant right) { | |
62 if (left.isInt() && right.isInt()) { | |
63 IntConstant leftInt = left; | |
64 IntConstant rightInt = right; | |
65 int resultValue = foldInts(leftInt.value, rightInt.value); | |
66 if (resultValue === null) return null; | |
67 return new IntConstant(resultValue); | |
68 } | |
69 return null; | |
70 } | |
71 | |
72 abstract int foldInts(int left, int right); | |
73 } | |
74 | |
75 class BitOrOperation extends BinaryIntOperation { | |
76 const BitOrOperation(); | |
77 int foldInts(int left, int right) => left | right; | |
78 } | |
79 | |
80 class BitAndOperation extends BinaryIntOperation { | |
81 const BitAndOperation(); | |
82 int foldInts(int left, int right) => left & right; | |
83 } | |
84 | |
85 class BitXorOperation extends BinaryIntOperation { | |
86 const BitXorOperation(); | |
87 int foldInts(int left, int right) => left ^ right; | |
88 } | |
89 | |
90 class ShiftLeftOperation extends BinaryIntOperation { | |
91 const ShiftLeftOperation(); | |
92 int foldInts(int left, int right) { | |
93 // TODO(floitsch): find a better way to guard against excessive shifts to | |
94 // the left. | |
95 if (right > 100 || right < 0) return null; | |
96 return left << right; | |
97 } | |
98 } | |
99 | |
100 class ShiftRightOperation extends BinaryIntOperation { | |
101 const ShiftRightOperation(); | |
102 int foldInts(int left, int right) { | |
103 if (right < 0) return null; | |
104 return left >> right; | |
105 } | |
106 } | |
107 | |
108 class BinaryBoolOperation implements BinaryOperation { | |
109 const BinaryBoolOperation(); | |
110 Constant fold(Constant left, Constant right) { | |
111 if (left.isBool() && right.isBool()) { | |
112 BoolConstant leftBool = left; | |
113 BoolConstant rightBool = right; | |
114 bool resultValue = foldBools(leftBool.value, rightBool.value); | |
115 return new BoolConstant(resultValue); | |
116 } | |
117 return null; | |
118 } | |
119 | |
120 abstract bool foldBools(bool left, bool right); | |
121 } | |
122 | |
123 class BooleanAnd extends BinaryBoolOperation { | |
124 const BooleanAnd(); | |
125 bool foldBools(bool left, bool right) => left && right; | |
126 } | |
127 | |
128 class BooleanOr extends BinaryBoolOperation { | |
129 const BooleanOr(); | |
130 bool foldBools(bool left, bool right) => left || right; | |
131 } | |
132 | |
133 class ArithmeticNumOperation implements BinaryOperation { | |
134 const ArithmeticNumOperation(); | |
135 Constant fold(Constant left, Constant right) { | |
136 if (left.isNum() && right.isNum()) { | |
137 NumConstant leftNum = left; | |
138 NumConstant rightNum = right; | |
139 num foldedValue; | |
140 if (left.isInt() && right.isInt()) { | |
141 foldedValue = foldInts(leftNum.value, rightNum.value); | |
142 } else { | |
143 foldedValue = foldNums(leftNum.value, rightNum.value); | |
144 } | |
145 // A division by 0 means that we might not have a folded value. | |
146 if (foldedValue === null) return null; | |
147 if (left.isInt() && right.isInt() && !isDivide()) { | |
148 assert(foldedValue is int); | |
149 return new IntConstant(foldedValue); | |
150 } else { | |
151 return new DoubleConstant(foldedValue); | |
152 } | |
153 } | |
154 } | |
155 | |
156 bool isDivide() => false; | |
157 num foldInts(int left, int right) => foldNums(left, right); | |
158 abstract num foldNums(num left, num right); | |
159 } | |
160 | |
161 class SubtractOperation extends ArithmeticNumOperation { | |
162 const SubtractOperation(); | |
163 num foldNums(num left, num right) => left - right; | |
164 } | |
165 | |
166 class MultiplyOperation extends ArithmeticNumOperation { | |
167 const MultiplyOperation(); | |
168 num foldNums(num left, num right) => left * right; | |
169 } | |
170 | |
171 class ModuloOperation extends ArithmeticNumOperation { | |
172 const ModuloOperation(); | |
173 int foldInts(int left, int right) { | |
174 if (right == 0) return null; | |
175 return left % right; | |
176 } | |
177 num foldNums(num left, num right) => left % right; | |
178 } | |
179 | |
180 class TruncatingDivideOperation extends ArithmeticNumOperation { | |
181 const TruncatingDivideOperation(); | |
182 int foldInts(int left, int right) { | |
183 if (right == 0) return null; | |
184 return left ~/ right; | |
185 } | |
186 num foldNums(num left, num right) => left ~/ right; | |
187 } | |
188 | |
189 class DivideOperation extends ArithmeticNumOperation { | |
190 const DivideOperation(); | |
191 num foldNums(num left, num right) => left / right; | |
192 bool isDivide() => true; | |
193 } | |
194 | |
195 class AddOperation implements BinaryOperation { | |
196 const AddOperation(); | |
197 Constant fold(Constant left, Constant right) { | |
198 if (left.isInt() && right.isInt()) { | |
199 IntConstant leftInt = left; | |
200 IntConstant rightInt = right; | |
201 return new IntConstant(leftInt.value + rightInt.value); | |
202 } else if (left.isNum() && right.isNum()) { | |
203 NumConstant leftNum = left; | |
204 NumConstant rightNum = right; | |
205 return new DoubleConstant(leftNum.value + rightNum.value); | |
206 } else if (left.isString() && !right.isObject()) { | |
207 PrimitiveConstant primitiveRight = right; | |
208 DartString rightDartString = primitiveRight.toDartString(); | |
209 StringConstant leftString = left; | |
210 if (rightDartString.isEmpty()) { | |
211 return left; | |
212 } else if (leftString.value.isEmpty()) { | |
213 return new StringConstant(rightDartString); | |
214 } else { | |
215 DartString concatenated = | |
216 new ConsDartString(leftString.value, rightDartString); | |
217 return new StringConstant(concatenated); | |
218 } | |
219 } else { | |
220 return null; | |
221 } | |
222 } | |
223 } | |
224 | |
225 class RelationalNumOperation implements BinaryOperation { | |
226 const RelationalNumOperation(); | |
227 Constant fold(Constant left, Constant right) { | |
228 if (left.isNum() && right.isNum()) { | |
229 NumConstant leftNum = left; | |
230 NumConstant rightNum = right; | |
231 bool foldedValue = foldNums(leftNum.value, rightNum.value); | |
232 assert(foldedValue != null); | |
233 return new BoolConstant(foldedValue); | |
234 } | |
235 } | |
236 | |
237 abstract bool foldNums(num left, num right); | |
238 } | |
239 | |
240 class LessOperation extends RelationalNumOperation { | |
241 const LessOperation(); | |
242 bool foldNums(num left, num right) => left < right; | |
243 } | |
244 | |
245 class LessEqualOperation extends RelationalNumOperation { | |
246 const LessEqualOperation(); | |
247 bool foldNums(num left, num right) => left <= right; | |
248 } | |
249 | |
250 class GreaterOperation extends RelationalNumOperation { | |
251 const GreaterOperation(); | |
252 bool foldNums(num left, num right) => left > right; | |
253 } | |
254 | |
255 class GreaterEqualOperation extends RelationalNumOperation { | |
256 const GreaterEqualOperation(); | |
257 bool foldNums(num left, num right) => left >= right; | |
258 } | |
259 | |
260 class EqualsOperation implements BinaryOperation { | |
261 const EqualsOperation(); | |
262 Constant fold(Constant left, Constant right) { | |
263 if (left.isNum() && right.isNum()) { | |
264 // Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0, | |
265 // and 1 == 1.0. | |
266 NumConstant leftNum = left; | |
267 NumConstant rightNum = right; | |
268 return new BoolConstant(leftNum.value == rightNum.value); | |
269 } | |
270 if (left.isConstructedObject()) { | |
271 // Unless we know that the user-defined object does not implement the | |
272 // equality operator we cannot fold here. | |
273 return null; | |
274 } | |
275 return new BoolConstant(left == right); | |
276 } | |
277 } | |
278 | |
279 class IdentityOperation implements BinaryOperation { | |
280 const IdentityOperation(); | |
281 Constant fold(Constant left, Constant right) { | |
282 return new BoolConstant(left == right); | |
283 } | |
284 } | |
OLD | NEW |