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