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