// // 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"); } /// /// Constant expression folder for binary operations. /// /// Returns null if the expression can not be folded. /// 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; } } }