cbb19e240d
Review URL: https://chromiumcodereview.appspot.com//10553007 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8778 260f80e4-7a28-3924-810f-c04153c831b5
310 lines
9.5 KiB
Dart
310 lines
9.5 KiB
Dart
// Copyright (c) 2012, 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.
|
|
|
|
interface Operation {
|
|
final SourceString name;
|
|
bool isUserDefinable();
|
|
}
|
|
|
|
interface UnaryOperation extends Operation {
|
|
/** Returns [:null:] if it was unable to fold the operation. */
|
|
Constant fold(Constant constant);
|
|
}
|
|
|
|
class BitNotOperation implements UnaryOperation {
|
|
final SourceString name = const SourceString('~');
|
|
bool isUserDefinable() => true;
|
|
const BitNotOperation();
|
|
Constant fold(Constant constant) {
|
|
if (constant.isInt()) {
|
|
IntConstant intConstant = constant;
|
|
return new IntConstant(~intConstant.value);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class NegateOperation implements UnaryOperation {
|
|
final SourceString name = const SourceString('negate');
|
|
bool isUserDefinable() => true;
|
|
const NegateOperation();
|
|
Constant fold(Constant constant) {
|
|
if (constant.isInt()) {
|
|
IntConstant intConstant = constant;
|
|
return new IntConstant(-intConstant.value);
|
|
}
|
|
if (constant.isDouble()) {
|
|
DoubleConstant doubleConstant = constant;
|
|
return new DoubleConstant(-doubleConstant.value);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
class NotOperation implements UnaryOperation {
|
|
final SourceString name = const SourceString('!');
|
|
bool isUserDefinable() => true;
|
|
const NotOperation();
|
|
Constant fold(Constant constant) {
|
|
if (constant.isBool()) {
|
|
BoolConstant boolConstant = constant;
|
|
return boolConstant.negate();
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
interface BinaryOperation extends Operation {
|
|
/** Returns [:null:] if it was unable to fold the operation. */
|
|
Constant fold(Constant left, Constant right);
|
|
}
|
|
|
|
/**
|
|
* Operations that only work if both arguments are integers.
|
|
*/
|
|
class BinaryIntOperation implements BinaryOperation {
|
|
bool isUserDefinable() => true;
|
|
const BinaryIntOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isInt() && right.isInt()) {
|
|
IntConstant leftInt = left;
|
|
IntConstant rightInt = right;
|
|
int resultValue = foldInts(leftInt.value, rightInt.value);
|
|
if (resultValue === null) return null;
|
|
return new IntConstant(resultValue);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
abstract int foldInts(int left, int right);
|
|
}
|
|
|
|
class BitOrOperation extends BinaryIntOperation {
|
|
final SourceString name = const SourceString('|');
|
|
const BitOrOperation();
|
|
int foldInts(int left, int right) => left | right;
|
|
}
|
|
|
|
class BitAndOperation extends BinaryIntOperation {
|
|
final SourceString name = const SourceString('&');
|
|
const BitAndOperation();
|
|
int foldInts(int left, int right) => left & right;
|
|
}
|
|
|
|
class BitXorOperation extends BinaryIntOperation {
|
|
final SourceString name = const SourceString('^');
|
|
const BitXorOperation();
|
|
int foldInts(int left, int right) => left ^ right;
|
|
}
|
|
|
|
class ShiftLeftOperation extends BinaryIntOperation {
|
|
final SourceString name = const SourceString('<<');
|
|
const ShiftLeftOperation();
|
|
int foldInts(int left, int right) {
|
|
// TODO(floitsch): find a better way to guard against excessive shifts to
|
|
// the left.
|
|
if (right > 100 || right < 0) return null;
|
|
return left << right;
|
|
}
|
|
}
|
|
|
|
class ShiftRightOperation extends BinaryIntOperation {
|
|
final SourceString name = const SourceString('>>');
|
|
const ShiftRightOperation();
|
|
int foldInts(int left, int right) {
|
|
if (right < 0) return null;
|
|
return left >> right;
|
|
}
|
|
}
|
|
|
|
class BinaryBoolOperation implements BinaryOperation {
|
|
bool isUserDefinable() => false;
|
|
const BinaryBoolOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isBool() && right.isBool()) {
|
|
BoolConstant leftBool = left;
|
|
BoolConstant rightBool = right;
|
|
bool resultValue = foldBools(leftBool.value, rightBool.value);
|
|
return new BoolConstant(resultValue);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
abstract bool foldBools(bool left, bool right);
|
|
}
|
|
|
|
class BooleanAnd extends BinaryBoolOperation {
|
|
final SourceString name = const SourceString('&&');
|
|
const BooleanAnd();
|
|
bool foldBools(bool left, bool right) => left && right;
|
|
}
|
|
|
|
class BooleanOr extends BinaryBoolOperation {
|
|
final SourceString name = const SourceString('||');
|
|
const BooleanOr();
|
|
bool foldBools(bool left, bool right) => left || right;
|
|
}
|
|
|
|
class ArithmeticNumOperation implements BinaryOperation {
|
|
bool isUserDefinable() => true;
|
|
const ArithmeticNumOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isNum() && right.isNum()) {
|
|
NumConstant leftNum = left;
|
|
NumConstant rightNum = right;
|
|
num foldedValue;
|
|
if (left.isInt() && right.isInt()) {
|
|
foldedValue = foldInts(leftNum.value, rightNum.value);
|
|
} else {
|
|
foldedValue = foldNums(leftNum.value, rightNum.value);
|
|
}
|
|
// A division by 0 means that we might not have a folded value.
|
|
if (foldedValue === null) return null;
|
|
if (left.isInt() && right.isInt() && !isDivide()) {
|
|
assert(foldedValue is int);
|
|
return new IntConstant(foldedValue);
|
|
} else {
|
|
return new DoubleConstant(foldedValue);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
bool isDivide() => false;
|
|
num foldInts(int left, int right) => foldNums(left, right);
|
|
abstract num foldNums(num left, num right);
|
|
}
|
|
|
|
class SubtractOperation extends ArithmeticNumOperation {
|
|
final SourceString name = const SourceString('-');
|
|
const SubtractOperation();
|
|
num foldNums(num left, num right) => left - right;
|
|
}
|
|
|
|
class MultiplyOperation extends ArithmeticNumOperation {
|
|
final SourceString name = const SourceString('*');
|
|
const MultiplyOperation();
|
|
num foldNums(num left, num right) => left * right;
|
|
}
|
|
|
|
class ModuloOperation extends ArithmeticNumOperation {
|
|
final SourceString name = const SourceString('%');
|
|
const ModuloOperation();
|
|
int foldInts(int left, int right) {
|
|
if (right == 0) return null;
|
|
return left % right;
|
|
}
|
|
num foldNums(num left, num right) => left % right;
|
|
}
|
|
|
|
class TruncatingDivideOperation extends ArithmeticNumOperation {
|
|
final SourceString name = const SourceString('~/');
|
|
const TruncatingDivideOperation();
|
|
int foldInts(int left, int right) {
|
|
if (right == 0) return null;
|
|
return left ~/ right;
|
|
}
|
|
num foldNums(num left, num right) => left ~/ right;
|
|
}
|
|
|
|
class DivideOperation extends ArithmeticNumOperation {
|
|
final SourceString name = const SourceString('/');
|
|
const DivideOperation();
|
|
num foldNums(num left, num right) => left / right;
|
|
bool isDivide() => true;
|
|
}
|
|
|
|
class AddOperation implements BinaryOperation {
|
|
final SourceString name = const SourceString('+');
|
|
bool isUserDefinable() => true;
|
|
const AddOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isInt() && right.isInt()) {
|
|
IntConstant leftInt = left;
|
|
IntConstant rightInt = right;
|
|
return new IntConstant(leftInt.value + rightInt.value);
|
|
} else if (left.isNum() && right.isNum()) {
|
|
NumConstant leftNum = left;
|
|
NumConstant rightNum = right;
|
|
return new DoubleConstant(leftNum.value + rightNum.value);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
class RelationalNumOperation implements BinaryOperation {
|
|
bool isUserDefinable() => true;
|
|
const RelationalNumOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isNum() && right.isNum()) {
|
|
NumConstant leftNum = left;
|
|
NumConstant rightNum = right;
|
|
bool foldedValue = foldNums(leftNum.value, rightNum.value);
|
|
assert(foldedValue != null);
|
|
return new BoolConstant(foldedValue);
|
|
}
|
|
}
|
|
|
|
abstract bool foldNums(num left, num right);
|
|
}
|
|
|
|
class LessOperation extends RelationalNumOperation {
|
|
final SourceString name = const SourceString('<');
|
|
const LessOperation();
|
|
bool foldNums(num left, num right) => left < right;
|
|
}
|
|
|
|
class LessEqualOperation extends RelationalNumOperation {
|
|
final SourceString name = const SourceString('<=');
|
|
const LessEqualOperation();
|
|
bool foldNums(num left, num right) => left <= right;
|
|
}
|
|
|
|
class GreaterOperation extends RelationalNumOperation {
|
|
final SourceString name = const SourceString('>');
|
|
const GreaterOperation();
|
|
bool foldNums(num left, num right) => left > right;
|
|
}
|
|
|
|
class GreaterEqualOperation extends RelationalNumOperation {
|
|
final SourceString name = const SourceString('>=');
|
|
const GreaterEqualOperation();
|
|
bool foldNums(num left, num right) => left >= right;
|
|
}
|
|
|
|
class EqualsOperation implements BinaryOperation {
|
|
final SourceString name = const SourceString('==');
|
|
bool isUserDefinable() => true;
|
|
const EqualsOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
if (left.isNum() && right.isNum()) {
|
|
// Numbers need to be treated specially because: NaN != NaN, -0.0 == 0.0,
|
|
// and 1 == 1.0.
|
|
NumConstant leftNum = left;
|
|
NumConstant rightNum = right;
|
|
return new BoolConstant(leftNum.value == rightNum.value);
|
|
}
|
|
if (left.isConstructedObject()) {
|
|
// Unless we know that the user-defined object does not implement the
|
|
// equality operator we cannot fold here.
|
|
return null;
|
|
}
|
|
return new BoolConstant(left == right);
|
|
}
|
|
}
|
|
|
|
class IdentityOperation implements BinaryOperation {
|
|
final SourceString name = const SourceString('===');
|
|
bool isUserDefinable() => false;
|
|
const IdentityOperation();
|
|
Constant fold(Constant left, Constant right) {
|
|
// In order to preserve runtime semantics which says that NaN !== NaN don't
|
|
// constant fold NaN === NaN. Otherwise the output depends on inlined
|
|
// variables and other optimizations.
|
|
if (left.isNaN() && right.isNaN()) return null;
|
|
return new BoolConstant(left == right);
|
|
}
|
|
}
|