966bba02bb
Former-commit-id: bb0468d0f257ff100aa895eb5fe583fb5dfbf900
1203 lines
38 KiB
C#
1203 lines
38 KiB
C#
//
|
|
// cfold.cs: Constant Folding
|
|
//
|
|
// Author:
|
|
// Miguel de Icaza (miguel@ximian.com)
|
|
// Marek Safar (marek.safar@seznam.cz)
|
|
//
|
|
// Copyright 2002, 2003 Ximian, Inc.
|
|
// Copyright 2003-2011, Novell, Inc.
|
|
//
|
|
using System;
|
|
|
|
namespace Mono.CSharp {
|
|
|
|
public static class ConstantFold
|
|
{
|
|
public static TypeSpec[] CreateBinaryPromotionsTypes (BuiltinTypes types)
|
|
{
|
|
return new TypeSpec[] {
|
|
types.Decimal, types.Double, types.Float,
|
|
types.ULong, types.Long, types.UInt
|
|
};
|
|
}
|
|
|
|
//
|
|
// Performs the numeric promotions on the left and right expresions
|
|
// and deposits the results on `lc' and `rc'.
|
|
//
|
|
// On success, the types of `lc' and `rc' on output will always match,
|
|
// and the pair will be one of:
|
|
//
|
|
// TODO: BinaryFold should be called as an optimization step only,
|
|
// error checking here is weak
|
|
//
|
|
static bool DoBinaryNumericPromotions (ResolveContext rc, ref Constant left, ref Constant right)
|
|
{
|
|
TypeSpec ltype = left.Type;
|
|
TypeSpec rtype = right.Type;
|
|
|
|
foreach (TypeSpec t in rc.BuiltinTypes.BinaryPromotionsTypes) {
|
|
if (t == ltype)
|
|
return t == rtype || ConvertPromotion (rc, ref right, ref left, t);
|
|
|
|
if (t == rtype)
|
|
return t == ltype || ConvertPromotion (rc, ref left, ref right, t);
|
|
}
|
|
|
|
left = left.ConvertImplicitly (rc.BuiltinTypes.Int);
|
|
right = right.ConvertImplicitly (rc.BuiltinTypes.Int);
|
|
return left != null && right != null;
|
|
}
|
|
|
|
static bool ConvertPromotion (ResolveContext rc, ref Constant prim, ref Constant second, TypeSpec type)
|
|
{
|
|
Constant c = prim.ConvertImplicitly (type);
|
|
if (c != null) {
|
|
prim = c;
|
|
return true;
|
|
}
|
|
|
|
if (type.BuiltinType == BuiltinTypeSpec.Type.UInt) {
|
|
type = rc.BuiltinTypes.Long;
|
|
prim = prim.ConvertImplicitly (type);
|
|
second = second.ConvertImplicitly (type);
|
|
return prim != null && second != null;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
internal static void Error_CompileTimeOverflow (ResolveContext rc, Location loc)
|
|
{
|
|
rc.Report.Error (220, loc, "The operation overflows at compile time in checked mode");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constant expression folder for binary operations.
|
|
///
|
|
/// Returns null if the expression can not be folded.
|
|
/// </summary>
|
|
static public Constant BinaryFold (ResolveContext ec, Binary.Operator oper,
|
|
Constant left, Constant right, Location loc)
|
|
{
|
|
Constant result = null;
|
|
|
|
if (left is EmptyConstantCast)
|
|
return BinaryFold (ec, oper, ((EmptyConstantCast)left).child, right, loc);
|
|
|
|
if (left is SideEffectConstant) {
|
|
result = BinaryFold (ec, oper, ((SideEffectConstant) left).value, right, loc);
|
|
if (result == null)
|
|
return null;
|
|
return new SideEffectConstant (result, left, loc);
|
|
}
|
|
|
|
if (right is EmptyConstantCast)
|
|
return BinaryFold (ec, oper, left, ((EmptyConstantCast)right).child, loc);
|
|
|
|
if (right is SideEffectConstant) {
|
|
result = BinaryFold (ec, oper, left, ((SideEffectConstant) right).value, loc);
|
|
if (result == null)
|
|
return null;
|
|
return new SideEffectConstant (result, right, loc);
|
|
}
|
|
|
|
TypeSpec lt = left.Type;
|
|
TypeSpec rt = right.Type;
|
|
bool bool_res;
|
|
|
|
if (lt.BuiltinType == BuiltinTypeSpec.Type.Bool && lt == rt) {
|
|
bool lv = (bool) left.GetValue ();
|
|
bool rv = (bool) right.GetValue ();
|
|
switch (oper) {
|
|
case Binary.Operator.BitwiseAnd:
|
|
case Binary.Operator.LogicalAnd:
|
|
return new BoolConstant (ec.BuiltinTypes, lv && rv, left.Location);
|
|
case Binary.Operator.BitwiseOr:
|
|
case Binary.Operator.LogicalOr:
|
|
return new BoolConstant (ec.BuiltinTypes, lv || rv, left.Location);
|
|
case Binary.Operator.ExclusiveOr:
|
|
return new BoolConstant (ec.BuiltinTypes, lv ^ rv, left.Location);
|
|
case Binary.Operator.Equality:
|
|
return new BoolConstant (ec.BuiltinTypes, lv == rv, left.Location);
|
|
case Binary.Operator.Inequality:
|
|
return new BoolConstant (ec.BuiltinTypes, lv != rv, left.Location);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// During an enum evaluation, none of the rules are valid
|
|
// Not sure whether it is bug in csc or in documentation
|
|
//
|
|
if (ec.HasSet (ResolveContext.Options.EnumScope)){
|
|
if (left is EnumConstant)
|
|
left = ((EnumConstant) left).Child;
|
|
|
|
if (right is EnumConstant)
|
|
right = ((EnumConstant) right).Child;
|
|
} else if (left is EnumConstant && rt == lt) {
|
|
switch (oper){
|
|
///
|
|
/// E operator |(E x, E y);
|
|
/// E operator &(E x, E y);
|
|
/// E operator ^(E x, E y);
|
|
///
|
|
case Binary.Operator.BitwiseOr:
|
|
case Binary.Operator.BitwiseAnd:
|
|
case Binary.Operator.ExclusiveOr:
|
|
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
|
|
if (result != null)
|
|
result = result.Reduce (ec, lt);
|
|
return result;
|
|
|
|
///
|
|
/// U operator -(E x, E y);
|
|
///
|
|
case Binary.Operator.Subtraction:
|
|
result = BinaryFold (ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
|
|
if (result != null)
|
|
result = result.Reduce (ec, EnumSpec.GetUnderlyingType (lt));
|
|
return result;
|
|
|
|
///
|
|
/// bool operator ==(E x, E y);
|
|
/// bool operator !=(E x, E y);
|
|
/// bool operator <(E x, E y);
|
|
/// bool operator >(E x, E y);
|
|
/// bool operator <=(E x, E y);
|
|
/// bool operator >=(E x, E y);
|
|
///
|
|
case Binary.Operator.Equality:
|
|
case Binary.Operator.Inequality:
|
|
case Binary.Operator.LessThan:
|
|
case Binary.Operator.GreaterThan:
|
|
case Binary.Operator.LessThanOrEqual:
|
|
case Binary.Operator.GreaterThanOrEqual:
|
|
return BinaryFold(ec, oper, ((EnumConstant)left).Child, ((EnumConstant)right).Child, loc);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
switch (oper){
|
|
case Binary.Operator.BitwiseOr:
|
|
//
|
|
// bool? operator |(bool? x, bool? y);
|
|
//
|
|
if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
|
|
(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
|
|
var b = new Binary (oper, left, right).ResolveOperator (ec);
|
|
|
|
// false | null => null
|
|
// null | false => null
|
|
if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
|
|
return Nullable.LiftedNull.CreateFromExpression (ec, b);
|
|
|
|
// true | null => true
|
|
// null | true => true
|
|
return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, true, loc), b);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
if (left is IntConstant){
|
|
int res = ((IntConstant) left).Value | ((IntConstant) right).Value;
|
|
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is UIntConstant){
|
|
uint res = ((UIntConstant)left).Value | ((UIntConstant)right).Value;
|
|
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is LongConstant){
|
|
long res = ((LongConstant)left).Value | ((LongConstant)right).Value;
|
|
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is ULongConstant){
|
|
ulong res = ((ULongConstant)left).Value |
|
|
((ULongConstant)right).Value;
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
break;
|
|
|
|
case Binary.Operator.BitwiseAnd:
|
|
//
|
|
// bool? operator &(bool? x, bool? y);
|
|
//
|
|
if ((lt.BuiltinType == BuiltinTypeSpec.Type.Bool && right is NullLiteral) ||
|
|
(rt.BuiltinType == BuiltinTypeSpec.Type.Bool && left is NullLiteral)) {
|
|
var b = new Binary (oper, left, right).ResolveOperator (ec);
|
|
|
|
// false & null => false
|
|
// null & false => false
|
|
if ((right is NullLiteral && left.IsDefaultValue) || (left is NullLiteral && right.IsDefaultValue))
|
|
return ReducedExpression.Create (new BoolConstant (ec.BuiltinTypes, false, loc), b);
|
|
|
|
// true & null => null
|
|
// null & true => null
|
|
return Nullable.LiftedNull.CreateFromExpression (ec, b);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
///
|
|
/// int operator &(int x, int y);
|
|
/// uint operator &(uint x, uint y);
|
|
/// long operator &(long x, long y);
|
|
/// ulong operator &(ulong x, ulong y);
|
|
///
|
|
if (left is IntConstant){
|
|
int res = ((IntConstant) left).Value & ((IntConstant) right).Value;
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is UIntConstant){
|
|
uint res = ((UIntConstant)left).Value & ((UIntConstant)right).Value;
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is LongConstant){
|
|
long res = ((LongConstant)left).Value & ((LongConstant)right).Value;
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is ULongConstant){
|
|
ulong res = ((ULongConstant)left).Value &
|
|
((ULongConstant)right).Value;
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
break;
|
|
|
|
case Binary.Operator.ExclusiveOr:
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
if (left is IntConstant){
|
|
int res = ((IntConstant) left).Value ^ ((IntConstant) right).Value;
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is UIntConstant){
|
|
uint res = ((UIntConstant)left).Value ^ ((UIntConstant)right).Value;
|
|
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is LongConstant){
|
|
long res = ((LongConstant)left).Value ^ ((LongConstant)right).Value;
|
|
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is ULongConstant){
|
|
ulong res = ((ULongConstant)left).Value ^
|
|
((ULongConstant)right).Value;
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
break;
|
|
|
|
case Binary.Operator.Addition:
|
|
//
|
|
// If both sides are strings, then concatenate
|
|
//
|
|
// string operator + (string x, string y)
|
|
//
|
|
if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
|
|
if (lt == rt)
|
|
return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
|
|
left.Location);
|
|
|
|
if (lt == InternalType.NullLiteral || left.IsNull)
|
|
return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
|
|
|
|
if (rt == InternalType.NullLiteral || right.IsNull)
|
|
return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
|
|
|
|
return null;
|
|
}
|
|
|
|
//
|
|
// string operator + (string x, object y)
|
|
//
|
|
if (lt == InternalType.NullLiteral) {
|
|
if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
|
|
return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
|
|
|
|
if (lt == rt) {
|
|
ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
|
|
"+", lt.GetSignatureForError (), rt.GetSignatureForError ());
|
|
return null;
|
|
}
|
|
|
|
return right;
|
|
}
|
|
|
|
//
|
|
// string operator + (object x, string y)
|
|
//
|
|
if (rt == InternalType.NullLiteral) {
|
|
if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
|
|
return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
|
|
|
|
return left;
|
|
}
|
|
|
|
//
|
|
// handle "E operator + (E x, U y)"
|
|
// handle "E operator + (Y y, E x)"
|
|
//
|
|
EnumConstant lc = left as EnumConstant;
|
|
EnumConstant rc = right as EnumConstant;
|
|
if (lc != null || rc != null){
|
|
if (lc == null) {
|
|
lc = rc;
|
|
lt = lc.Type;
|
|
right = left;
|
|
}
|
|
|
|
// U has to be implicitly convetible to E.base
|
|
right = right.ConvertImplicitly (lc.Child.Type);
|
|
if (right == null)
|
|
return null;
|
|
|
|
result = BinaryFold (ec, oper, lc.Child, right, loc);
|
|
if (result == null)
|
|
return null;
|
|
|
|
result = result.Reduce (ec, lt);
|
|
if (result == null || lt.IsEnum)
|
|
return result;
|
|
|
|
return new EnumConstant (result, lt);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
try {
|
|
if (left is DoubleConstant){
|
|
double res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DoubleConstant) left).Value +
|
|
((DoubleConstant) right).Value);
|
|
else
|
|
res = unchecked (((DoubleConstant) left).Value +
|
|
((DoubleConstant) right).Value);
|
|
|
|
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
if (left is FloatConstant){
|
|
double a, b, res;
|
|
a = ((FloatConstant) left).DoubleValue;
|
|
b = ((FloatConstant) right).DoubleValue;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (a + b);
|
|
else
|
|
res = unchecked (a + b);
|
|
|
|
result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is ULongConstant){
|
|
ulong res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((ULongConstant) left).Value +
|
|
((ULongConstant) right).Value);
|
|
else
|
|
res = unchecked (((ULongConstant) left).Value +
|
|
((ULongConstant) right).Value);
|
|
|
|
result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is LongConstant){
|
|
long res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((LongConstant) left).Value +
|
|
((LongConstant) right).Value);
|
|
else
|
|
res = unchecked (((LongConstant) left).Value +
|
|
((LongConstant) right).Value);
|
|
|
|
result = new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is UIntConstant){
|
|
uint res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((UIntConstant) left).Value +
|
|
((UIntConstant) right).Value);
|
|
else
|
|
res = unchecked (((UIntConstant) left).Value +
|
|
((UIntConstant) right).Value);
|
|
|
|
result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is IntConstant){
|
|
int res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((IntConstant) left).Value +
|
|
((IntConstant) right).Value);
|
|
else
|
|
res = unchecked (((IntConstant) left).Value +
|
|
((IntConstant) right).Value);
|
|
|
|
result = new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is DecimalConstant) {
|
|
decimal res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DecimalConstant) left).Value +
|
|
((DecimalConstant) right).Value);
|
|
else
|
|
res = unchecked (((DecimalConstant) left).Value +
|
|
((DecimalConstant) right).Value);
|
|
|
|
result = new DecimalConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
} catch (OverflowException){
|
|
Error_CompileTimeOverflow (ec, loc);
|
|
}
|
|
|
|
return result;
|
|
|
|
case Binary.Operator.Subtraction:
|
|
//
|
|
// handle "E operator - (E x, U y)"
|
|
// handle "E operator - (Y y, E x)"
|
|
//
|
|
lc = left as EnumConstant;
|
|
rc = right as EnumConstant;
|
|
if (lc != null || rc != null) {
|
|
TypeSpec res_type;
|
|
if (lc == null) {
|
|
res_type = right.Type;
|
|
|
|
// Y has to be implicitly convertible to E.base
|
|
left = left.ConvertImplicitly (rc.Child.Type);
|
|
if (left == null)
|
|
return null;
|
|
|
|
right = rc.Child;
|
|
} else {
|
|
res_type = left.Type;
|
|
|
|
// U has to be implicitly convertible to E.base
|
|
right = right.ConvertImplicitly (lc.Child.Type);
|
|
if (right == null)
|
|
return null;
|
|
|
|
left = lc.Child;
|
|
}
|
|
|
|
result = BinaryFold (ec, oper, left, right, loc);
|
|
if (result == null)
|
|
return null;
|
|
|
|
result = result.Reduce (ec, res_type);
|
|
if (result == null)
|
|
return null;
|
|
|
|
return new EnumConstant (result, res_type);
|
|
}
|
|
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
try {
|
|
if (left is DoubleConstant){
|
|
double res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DoubleConstant) left).Value -
|
|
((DoubleConstant) right).Value);
|
|
else
|
|
res = unchecked (((DoubleConstant) left).Value -
|
|
((DoubleConstant) right).Value);
|
|
|
|
result = new DoubleConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is FloatConstant){
|
|
double a, b, res;
|
|
a = ((FloatConstant) left).DoubleValue;
|
|
b = ((FloatConstant) right).DoubleValue;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (a - b);
|
|
else
|
|
res = unchecked (a - b);
|
|
|
|
result = new FloatConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is ULongConstant){
|
|
ulong res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((ULongConstant) left).Value -
|
|
((ULongConstant) right).Value);
|
|
else
|
|
res = unchecked (((ULongConstant) left).Value -
|
|
((ULongConstant) right).Value);
|
|
|
|
result = new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is LongConstant){
|
|
long res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((LongConstant) left).Value -
|
|
((LongConstant) right).Value);
|
|
else
|
|
res = unchecked (((LongConstant) left).Value -
|
|
((LongConstant) right).Value);
|
|
|
|
result = new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is UIntConstant){
|
|
uint res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((UIntConstant) left).Value -
|
|
((UIntConstant) right).Value);
|
|
else
|
|
res = unchecked (((UIntConstant) left).Value -
|
|
((UIntConstant) right).Value);
|
|
|
|
result = new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is IntConstant){
|
|
int res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((IntConstant) left).Value -
|
|
((IntConstant) right).Value);
|
|
else
|
|
res = unchecked (((IntConstant) left).Value -
|
|
((IntConstant) right).Value);
|
|
|
|
result = new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is DecimalConstant) {
|
|
decimal res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DecimalConstant) left).Value -
|
|
((DecimalConstant) right).Value);
|
|
else
|
|
res = unchecked (((DecimalConstant) left).Value -
|
|
((DecimalConstant) right).Value);
|
|
|
|
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else {
|
|
throw new Exception ( "Unexepected subtraction input: " + left);
|
|
}
|
|
} catch (OverflowException){
|
|
Error_CompileTimeOverflow (ec, loc);
|
|
}
|
|
|
|
return result;
|
|
|
|
case Binary.Operator.Multiply:
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
try {
|
|
if (left is DoubleConstant){
|
|
double res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DoubleConstant) left).Value *
|
|
((DoubleConstant) right).Value);
|
|
else
|
|
res = unchecked (((DoubleConstant) left).Value *
|
|
((DoubleConstant) right).Value);
|
|
|
|
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is FloatConstant){
|
|
double a, b, res;
|
|
a = ((FloatConstant) left).DoubleValue;
|
|
b = ((FloatConstant) right).DoubleValue;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (a * b);
|
|
else
|
|
res = unchecked (a * b);
|
|
|
|
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is ULongConstant){
|
|
ulong res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((ULongConstant) left).Value *
|
|
((ULongConstant) right).Value);
|
|
else
|
|
res = unchecked (((ULongConstant) left).Value *
|
|
((ULongConstant) right).Value);
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is LongConstant){
|
|
long res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((LongConstant) left).Value *
|
|
((LongConstant) right).Value);
|
|
else
|
|
res = unchecked (((LongConstant) left).Value *
|
|
((LongConstant) right).Value);
|
|
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is UIntConstant){
|
|
uint res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((UIntConstant) left).Value *
|
|
((UIntConstant) right).Value);
|
|
else
|
|
res = unchecked (((UIntConstant) left).Value *
|
|
((UIntConstant) right).Value);
|
|
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is IntConstant){
|
|
int res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((IntConstant) left).Value *
|
|
((IntConstant) right).Value);
|
|
else
|
|
res = unchecked (((IntConstant) left).Value *
|
|
((IntConstant) right).Value);
|
|
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is DecimalConstant) {
|
|
decimal res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DecimalConstant) left).Value *
|
|
((DecimalConstant) right).Value);
|
|
else
|
|
res = unchecked (((DecimalConstant) left).Value *
|
|
((DecimalConstant) right).Value);
|
|
|
|
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else {
|
|
throw new Exception ( "Unexepected multiply input: " + left);
|
|
}
|
|
} catch (OverflowException){
|
|
Error_CompileTimeOverflow (ec, loc);
|
|
}
|
|
break;
|
|
|
|
case Binary.Operator.Division:
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
try {
|
|
if (left is DoubleConstant){
|
|
double res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DoubleConstant) left).Value /
|
|
((DoubleConstant) right).Value);
|
|
else
|
|
res = unchecked (((DoubleConstant) left).Value /
|
|
((DoubleConstant) right).Value);
|
|
|
|
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is FloatConstant){
|
|
double a, b, res;
|
|
a = ((FloatConstant) left).DoubleValue;
|
|
b = ((FloatConstant) right).DoubleValue;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (a / b);
|
|
else
|
|
res = unchecked (a / b);
|
|
|
|
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is ULongConstant){
|
|
ulong res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((ULongConstant) left).Value /
|
|
((ULongConstant) right).Value);
|
|
else
|
|
res = unchecked (((ULongConstant) left).Value /
|
|
((ULongConstant) right).Value);
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is LongConstant){
|
|
long res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((LongConstant) left).Value /
|
|
((LongConstant) right).Value);
|
|
else
|
|
res = unchecked (((LongConstant) left).Value /
|
|
((LongConstant) right).Value);
|
|
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is UIntConstant){
|
|
uint res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((UIntConstant) left).Value /
|
|
((UIntConstant) right).Value);
|
|
else
|
|
res = unchecked (((UIntConstant) left).Value /
|
|
((UIntConstant) right).Value);
|
|
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is IntConstant){
|
|
int res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((IntConstant) left).Value /
|
|
((IntConstant) right).Value);
|
|
else
|
|
res = unchecked (((IntConstant) left).Value /
|
|
((IntConstant) right).Value);
|
|
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is DecimalConstant) {
|
|
decimal res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DecimalConstant) left).Value /
|
|
((DecimalConstant) right).Value);
|
|
else
|
|
res = unchecked (((DecimalConstant) left).Value /
|
|
((DecimalConstant) right).Value);
|
|
|
|
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else {
|
|
throw new Exception ( "Unexepected division input: " + left);
|
|
}
|
|
} catch (OverflowException){
|
|
Error_CompileTimeOverflow (ec, loc);
|
|
|
|
} catch (DivideByZeroException) {
|
|
ec.Report.Error (20, loc, "Division by constant zero");
|
|
}
|
|
|
|
break;
|
|
|
|
case Binary.Operator.Modulus:
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
try {
|
|
if (left is DoubleConstant){
|
|
double res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DoubleConstant) left).Value %
|
|
((DoubleConstant) right).Value);
|
|
else
|
|
res = unchecked (((DoubleConstant) left).Value %
|
|
((DoubleConstant) right).Value);
|
|
|
|
return new DoubleConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is FloatConstant){
|
|
double a, b, res;
|
|
a = ((FloatConstant) left).DoubleValue;
|
|
b = ((FloatConstant) right).DoubleValue;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (a % b);
|
|
else
|
|
res = unchecked (a % b);
|
|
|
|
return new FloatConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is ULongConstant){
|
|
ulong res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((ULongConstant) left).Value %
|
|
((ULongConstant) right).Value);
|
|
else
|
|
res = unchecked (((ULongConstant) left).Value %
|
|
((ULongConstant) right).Value);
|
|
|
|
return new ULongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is LongConstant){
|
|
long res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((LongConstant) left).Value %
|
|
((LongConstant) right).Value);
|
|
else
|
|
res = unchecked (((LongConstant) left).Value %
|
|
((LongConstant) right).Value);
|
|
|
|
return new LongConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is UIntConstant){
|
|
uint res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((UIntConstant) left).Value %
|
|
((UIntConstant) right).Value);
|
|
else
|
|
res = unchecked (((UIntConstant) left).Value %
|
|
((UIntConstant) right).Value);
|
|
|
|
return new UIntConstant (ec.BuiltinTypes, res, left.Location);
|
|
} else if (left is IntConstant){
|
|
int res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((IntConstant) left).Value %
|
|
((IntConstant) right).Value);
|
|
else
|
|
res = unchecked (((IntConstant) left).Value %
|
|
((IntConstant) right).Value);
|
|
|
|
return new IntConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
|
|
if (left is DecimalConstant) {
|
|
decimal res;
|
|
|
|
if (ec.ConstantCheckState)
|
|
res = checked (((DecimalConstant) left).Value %
|
|
((DecimalConstant) right).Value);
|
|
else
|
|
res = unchecked (((DecimalConstant) left).Value %
|
|
((DecimalConstant) right).Value);
|
|
|
|
return new DecimalConstant (ec.BuiltinTypes, res, left.Location);
|
|
}
|
|
|
|
throw new Exception ( "Unexepected modulus input: " + left);
|
|
} catch (DivideByZeroException){
|
|
ec.Report.Error (20, loc, "Division by constant zero");
|
|
} catch (OverflowException){
|
|
Error_CompileTimeOverflow (ec, loc);
|
|
}
|
|
break;
|
|
|
|
//
|
|
// There is no overflow checking on left shift
|
|
//
|
|
case Binary.Operator.LeftShift:
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
IntConstant ic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
|
|
if (ic == null){
|
|
return null;
|
|
}
|
|
|
|
int lshift_val = ic.Value;
|
|
switch (left.Type.BuiltinType) {
|
|
case BuiltinTypeSpec.Type.ULong:
|
|
return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value << lshift_val, left.Location);
|
|
case BuiltinTypeSpec.Type.Long:
|
|
return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value << lshift_val, left.Location);
|
|
case BuiltinTypeSpec.Type.UInt:
|
|
return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value << lshift_val, left.Location);
|
|
}
|
|
|
|
// null << value => null
|
|
if (left is NullLiteral)
|
|
return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
|
|
|
|
left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
|
|
if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
|
|
return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value << lshift_val, left.Location);
|
|
|
|
return null;
|
|
|
|
//
|
|
// There is no overflow checking on right shift
|
|
//
|
|
case Binary.Operator.RightShift:
|
|
if (left is NullLiteral && right is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
|
|
IntConstant sic = right.ConvertImplicitly (ec.BuiltinTypes.Int) as IntConstant;
|
|
if (sic == null){
|
|
return null;
|
|
}
|
|
int rshift_val = sic.Value;
|
|
switch (left.Type.BuiltinType) {
|
|
case BuiltinTypeSpec.Type.ULong:
|
|
return new ULongConstant (ec.BuiltinTypes, ((ULongConstant) left).Value >> rshift_val, left.Location);
|
|
case BuiltinTypeSpec.Type.Long:
|
|
return new LongConstant (ec.BuiltinTypes, ((LongConstant) left).Value >> rshift_val, left.Location);
|
|
case BuiltinTypeSpec.Type.UInt:
|
|
return new UIntConstant (ec.BuiltinTypes, ((UIntConstant) left).Value >> rshift_val, left.Location);
|
|
}
|
|
|
|
// null >> value => null
|
|
if (left is NullLiteral)
|
|
return (Constant) new Binary (oper, left, right).ResolveOperator (ec);
|
|
|
|
left = left.ConvertImplicitly (ec.BuiltinTypes.Int);
|
|
if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
|
|
return new IntConstant (ec.BuiltinTypes, ((IntConstant) left).Value >> rshift_val, left.Location);
|
|
|
|
return null;
|
|
|
|
case Binary.Operator.Equality:
|
|
if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
|
|
(left is Nullable.LiftedNull && right.IsNull) ||
|
|
(right is Nullable.LiftedNull && left.IsNull)) {
|
|
if (left.IsNull || right.IsNull) {
|
|
return ReducedExpression.Create (
|
|
new BoolConstant (ec.BuiltinTypes, left.IsNull == right.IsNull, left.Location),
|
|
new Binary (oper, left, right));
|
|
}
|
|
|
|
if (left is StringConstant && right is StringConstant)
|
|
return new BoolConstant (ec.BuiltinTypes,
|
|
((StringConstant) left).Value == ((StringConstant) right).Value, left.Location);
|
|
|
|
return null;
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value ==
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue ==
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value ==
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value ==
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value ==
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value ==
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
|
|
case Binary.Operator.Inequality:
|
|
if (TypeSpec.IsReferenceType (lt) && TypeSpec.IsReferenceType (rt) ||
|
|
(left is Nullable.LiftedNull && right.IsNull) ||
|
|
(right is Nullable.LiftedNull && left.IsNull)) {
|
|
if (left.IsNull || right.IsNull) {
|
|
return ReducedExpression.Create (
|
|
new BoolConstant (ec.BuiltinTypes, left.IsNull != right.IsNull, left.Location),
|
|
new Binary (oper, left, right));
|
|
}
|
|
|
|
if (left is StringConstant && right is StringConstant)
|
|
return new BoolConstant (ec.BuiltinTypes,
|
|
((StringConstant) left).Value != ((StringConstant) right).Value, left.Location);
|
|
|
|
return null;
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value !=
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue !=
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value !=
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value !=
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value !=
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value !=
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
|
|
case Binary.Operator.LessThan:
|
|
if (right is NullLiteral) {
|
|
if (left is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value <
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue <
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value <
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value <
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value <
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value <
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
|
|
case Binary.Operator.GreaterThan:
|
|
if (right is NullLiteral) {
|
|
if (left is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value >
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue >
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value >
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value >
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value >
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value >
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
|
|
case Binary.Operator.GreaterThanOrEqual:
|
|
if (right is NullLiteral) {
|
|
if (left is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value >=
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue >=
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value >=
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value >=
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value >=
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value >=
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
|
|
case Binary.Operator.LessThanOrEqual:
|
|
if (right is NullLiteral) {
|
|
if (left is NullLiteral) {
|
|
var lifted_int = new Nullable.NullableType (ec.BuiltinTypes.Int, loc);
|
|
lifted_int.ResolveAsType (ec);
|
|
return (Constant) new Binary (oper, lifted_int, right).ResolveOperator (ec);
|
|
}
|
|
}
|
|
|
|
if (!DoBinaryNumericPromotions (ec, ref left, ref right))
|
|
return null;
|
|
|
|
bool_res = false;
|
|
if (left is DoubleConstant)
|
|
bool_res = ((DoubleConstant) left).Value <=
|
|
((DoubleConstant) right).Value;
|
|
else if (left is FloatConstant)
|
|
bool_res = ((FloatConstant) left).DoubleValue <=
|
|
((FloatConstant) right).DoubleValue;
|
|
else if (left is ULongConstant)
|
|
bool_res = ((ULongConstant) left).Value <=
|
|
((ULongConstant) right).Value;
|
|
else if (left is LongConstant)
|
|
bool_res = ((LongConstant) left).Value <=
|
|
((LongConstant) right).Value;
|
|
else if (left is UIntConstant)
|
|
bool_res = ((UIntConstant) left).Value <=
|
|
((UIntConstant) right).Value;
|
|
else if (left is IntConstant)
|
|
bool_res = ((IntConstant) left).Value <=
|
|
((IntConstant) right).Value;
|
|
else
|
|
return null;
|
|
|
|
return new BoolConstant (ec.BuiltinTypes, bool_res, left.Location);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
}
|