X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fconstant.cs;h=608310c00adb7e2c8603f3eca0e1376af357eb4b;hb=2a23b6fa7ec1091a65cca42d38b8e1bc260d3a01;hp=34fdbfb86ce13002edbfb4201f900f9ceab75c5c;hpb=6c33f8c3615ebc33234c9d6cbe9641ef234aa099;p=mono.git diff --git a/mcs/gmcs/constant.cs b/mcs/gmcs/constant.cs old mode 100755 new mode 100644 index 34fdbfb86ce..608310c00ad --- a/mcs/gmcs/constant.cs +++ b/mcs/gmcs/constant.cs @@ -3,6 +3,7 @@ // // Author: // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@seznam.cz) // // (C) 2001 Ximian, Inc. // @@ -17,6 +18,12 @@ namespace Mono.CSharp { /// Base class for constants and literals. /// public abstract class Constant : Expression { + + protected Constant (Location loc) + { + this.loc = loc; + } + /// /// This is different from ToString in that ToString /// is supposed to be there for debugging purposes, @@ -38,6 +45,11 @@ namespace Mono.CSharp { /// public abstract object GetValue (); + public virtual object GetTypedValue () + { + return GetValue (); + } + /// /// Constants are always born in a fully resolved state /// @@ -62,7 +74,7 @@ namespace Mono.CSharp { DoubleConstant c = ConvertToDouble (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.double_type); + Error_ValueCannotBeConverted (loc, TypeManager.double_type, false); return c; } @@ -72,7 +84,7 @@ namespace Mono.CSharp { FloatConstant c = ConvertToFloat (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.float_type); + Error_ValueCannotBeConverted (loc, TypeManager.float_type, false); return c; } @@ -82,7 +94,7 @@ namespace Mono.CSharp { ULongConstant c = ConvertToULong (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint64_type); + Error_ValueCannotBeConverted (loc, TypeManager.uint64_type, false); return c; } @@ -92,7 +104,7 @@ namespace Mono.CSharp { LongConstant c = ConvertToLong (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int64_type); + Error_ValueCannotBeConverted (loc, TypeManager.int64_type, false); return c; } @@ -102,7 +114,7 @@ namespace Mono.CSharp { UIntConstant c = ConvertToUInt (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint32_type); + Error_ValueCannotBeConverted (loc, TypeManager.uint32_type, false); return c; } @@ -112,10 +124,155 @@ namespace Mono.CSharp { IntConstant c = ConvertToInt (); if (c == null) - Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int32_type); + Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false); return c; } + + public DecimalConstant ToDecimal (Location loc) + { + DecimalConstant c = ConvertToDecimal (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.decimal_type, false); + + return c; + } + + public virtual Constant ToType (Type type, Location loc) + { + if (Type == type) + return this; + + if (type == TypeManager.object_type) + return this; + + if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){ + Error_ValueCannotBeConverted (loc, type, false); + return null; + } + + // Special-case: The 0 literal can be converted to an enum value, + // and ImplicitStandardConversionExists will return true in that case. + if (IsZeroInteger && Type == TypeManager.int32_type && TypeManager.IsEnumType (type)) { + return new EnumConstant (this, type); + } + + bool fail; + object constant_value = TypeManager.ChangeType (GetValue (), type, out fail); + if (fail){ + Error_ValueCannotBeConverted (loc, type, false); + + // + // We should always catch the error before this is ever + // reached, by calling Convert.ImplicitStandardConversionExists + // + throw new Exception ( + String.Format ("LookupConstantValue: This should never be reached {0} {1}", Type, type)); + } + + Constant retval; + if (type == TypeManager.int32_type) + retval = new IntConstant ((int) constant_value, loc); + else if (type == TypeManager.uint32_type) + retval = new UIntConstant ((uint) constant_value, loc); + else if (type == TypeManager.int64_type) + retval = new LongConstant ((long) constant_value, loc); + else if (type == TypeManager.uint64_type) + retval = new ULongConstant ((ulong) constant_value, loc); + else if (type == TypeManager.float_type) + retval = new FloatConstant ((float) constant_value, loc); + else if (type == TypeManager.double_type) + retval = new DoubleConstant ((double) constant_value, loc); + else if (type == TypeManager.string_type) + retval = new StringConstant ((string) constant_value, loc); + else if (type == TypeManager.short_type) + retval = new ShortConstant ((short) constant_value, loc); + else if (type == TypeManager.ushort_type) + retval = new UShortConstant ((ushort) constant_value, loc); + else if (type == TypeManager.sbyte_type) + retval = new SByteConstant ((sbyte) constant_value, loc); + else if (type == TypeManager.byte_type) + retval = new ByteConstant ((byte) constant_value, loc); + else if (type == TypeManager.char_type) + retval = new CharConstant ((char) constant_value, loc); + else if (type == TypeManager.bool_type) + retval = new BoolConstant ((bool) constant_value, loc); + else if (type == TypeManager.decimal_type) + retval = new DecimalConstant ((decimal) constant_value, loc); + else + throw new Exception ("LookupConstantValue: Unhandled constant type: " + type); + + return retval; + } + + protected void CheckRange (EmitContext ec, ulong value, Type type, ulong max) + { + if (!ec.ConstantCheckState) + return; + + if (value > max) + throw new OverflowException (); + } + + protected void CheckRange (EmitContext ec, double value, Type type, long min, long max) + { + if (!ec.ConstantCheckState) + return; + + if (((value < min) || (value > max))) + throw new OverflowException (); + } + + protected void CheckUnsigned (EmitContext ec, long value, Type type) + { + if (!ec.ConstantCheckState) + return; + + if (value < 0) + throw new OverflowException (); + } + + public abstract Constant Reduce (EmitContext ec, Type target_type); + + /// + /// Attempts to do a compile-time folding of a constant cast. + /// + public Constant TryReduce (EmitContext ec, Type target_type, Location loc) + { + try { + return TryReduce (ec, target_type); + } + catch (OverflowException) { + if (ec.ConstantCheckState) { + Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", + this.GetValue (), TypeManager.CSharpName (target_type)); + } + return null; + } + } + + Constant TryReduce (EmitContext ec, Type target_type) + { + if (Type == target_type) + return this; + + if (TypeManager.IsEnumType (target_type)) { + Constant c = TryReduce (ec, TypeManager.EnumToUnderlying (target_type)); + if (c == null) + return null; + + return new EnumConstant (c, target_type); + } + + return Reduce (ec, target_type); + } + + + public virtual DecimalConstant ConvertToDecimal () + { + return null; + } public virtual DoubleConstant ConvertToDouble () { @@ -146,7 +303,13 @@ namespace Mono.CSharp { { return null; } + + public abstract Constant Increment (); + public abstract bool IsDefaultValue { + get; + } + public abstract bool IsNegative { get; } @@ -163,7 +326,8 @@ namespace Mono.CSharp { public class BoolConstant : Constant { public readonly bool Value; - public BoolConstant (bool val) + public BoolConstant (bool val, Location loc): + base (loc) { type = TypeManager.bool_type; eclass = ExprClass.Value; @@ -189,7 +353,18 @@ namespace Mono.CSharp { else ec.ig.Emit (OpCodes.Ldc_I4_0); } - + + public override Constant Increment () + { + throw new NotSupportedException (); + } + + public override bool IsDefaultValue { + get { + return !Value; + } + } + public override bool IsNegative { get { return false; @@ -199,12 +374,19 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == false; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + return null; + } + } public class ByteConstant : Constant { public readonly byte Value; - public ByteConstant (byte v) + public ByteConstant (byte v, Location loc): + base (loc) { type = TypeManager.byte_type; eclass = ExprClass.Value; @@ -228,34 +410,45 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () { - return new ULongConstant (Value); + return new ULongConstant (Value, loc); } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () { - return new UIntConstant (Value); + return new UIntConstant (Value, loc); } public override IntConstant ConvertToInt () { - return new IntConstant (Value); + return new IntConstant (Value, loc); } + public override Constant Increment () + { + return new ByteConstant (checked ((byte)(Value + 1)), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return false; @@ -265,12 +458,44 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) + return new ShortConstant ((short) Value, Location); + if (target_type == TypeManager.ushort_type) + return new UShortConstant ((ushort) Value, Location); + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint) Value, Location); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) + return new CharConstant ((char) Value, Location); + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class CharConstant : Constant { public readonly char Value; - public CharConstant (char v) + public CharConstant (char v, Location loc): + base (loc) { type = TypeManager.char_type; eclass = ExprClass.Value; @@ -323,34 +548,45 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () { - return new ULongConstant (Value); + return new ULongConstant (Value, loc); } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () { - return new UIntConstant (Value); + return new UIntConstant (Value, loc); } public override IntConstant ConvertToInt () { - return new IntConstant (Value); + return new IntConstant (Value, loc); + } + + public override Constant Increment () + { + return new CharConstant (checked ((char)(Value + 1)), loc); } + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return false; @@ -360,12 +596,46 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == '\0'; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint) Value, Location); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class SByteConstant : Constant { public readonly sbyte Value; - public SByteConstant (sbyte v) + public SByteConstant (sbyte v, Location loc): + base (loc) { type = TypeManager.sbyte_type; eclass = ExprClass.Value; @@ -389,25 +659,25 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () { if (Value >= 0) - return new ULongConstant ((ulong) Value); + return new ULongConstant ((ulong) Value, loc); return null; } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () @@ -417,9 +687,20 @@ namespace Mono.CSharp { public override IntConstant ConvertToInt () { - return new IntConstant (Value); + return new IntConstant (Value, loc); } + public override Constant Increment () + { + return new SByteConstant (checked((sbyte)(Value + 1)), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return Value < 0; @@ -429,12 +710,50 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckUnsigned (ec, Value, target_type); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.short_type) + return new ShortConstant ((short) Value, Location); + if (target_type == TypeManager.ushort_type) { + CheckUnsigned (ec, Value, target_type); + return new UShortConstant ((ushort) Value, Location); + } if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) { + CheckUnsigned (ec, Value, target_type); + return new UIntConstant ((uint) Value, Location); + } if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + CheckUnsigned (ec, Value, target_type); + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckUnsigned (ec, Value, target_type); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class ShortConstant : Constant { public readonly short Value; - public ShortConstant (short v) + public ShortConstant (short v, Location loc): + base (loc) { type = TypeManager.short_type; eclass = ExprClass.Value; @@ -458,12 +777,12 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () @@ -473,7 +792,7 @@ namespace Mono.CSharp { public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () @@ -483,7 +802,18 @@ namespace Mono.CSharp { public override IntConstant ConvertToInt () { - return new IntConstant (Value); + return new IntConstant (Value, loc); + } + + public override Constant Increment () + { + return new ShortConstant (checked((short)(Value + 1)), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } } public override bool IsZeroInteger { @@ -495,12 +825,54 @@ namespace Mono.CSharp { return Value < 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckUnsigned (ec, Value, target_type); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) { + CheckUnsigned (ec, Value, target_type); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + CheckUnsigned (ec, Value, target_type); + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class UShortConstant : Constant { public readonly ushort Value; - public UShortConstant (ushort v) + public UShortConstant (ushort v, Location loc): + base (loc) { type = TypeManager.ushort_type; eclass = ExprClass.Value; @@ -524,34 +896,45 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () { - return new ULongConstant (Value); + return new ULongConstant (Value, loc); } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () { - return new UIntConstant (Value); + return new UIntConstant (Value, loc); } public override IntConstant ConvertToInt () { - return new IntConstant (Value); + return new IntConstant (Value, loc); } + public override Constant Increment () + { + return new UShortConstant (checked((ushort)(Value + 1)), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return false; @@ -561,12 +944,49 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint) Value, Location); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } } public class IntConstant : Constant { public readonly int Value; - public IntConstant (int v) + public IntConstant (int v, Location loc): + base (loc) { type = TypeManager.int32_type; eclass = ExprClass.Value; @@ -640,14 +1060,19 @@ namespace Mono.CSharp { return Value; } + public override DecimalConstant ConvertToDecimal() + { + return new DecimalConstant (Value, loc); + } + public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () @@ -655,12 +1080,12 @@ namespace Mono.CSharp { if (Value < 0) return null; - return new ULongConstant ((ulong) Value); + return new ULongConstant ((ulong) Value, loc); } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () @@ -668,13 +1093,24 @@ namespace Mono.CSharp { if (Value < 0) return null; - return new UIntConstant ((uint) Value); + return new UIntConstant ((uint) Value, loc); } public override IntConstant ConvertToInt () { return this; } + + public override Constant Increment () + { + return new IntConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } public override bool IsNegative { get { @@ -685,12 +1121,55 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + CheckUnsigned (ec, Value, target_type); + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } } public class UIntConstant : Constant { public readonly uint Value; - public UIntConstant (uint v) + public UIntConstant (uint v, Location loc): + base (loc) { type = TypeManager.uint32_type; eclass = ExprClass.Value; @@ -714,22 +1193,22 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () { - return new ULongConstant (Value); + return new ULongConstant (Value, loc); } public override LongConstant ConvertToLong () { - return new LongConstant (Value); + return new LongConstant (Value, loc); } public override UIntConstant ConvertToUInt () @@ -741,7 +1220,18 @@ namespace Mono.CSharp { { return null; } - + + public override Constant Increment () + { + return new UIntConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return false; @@ -751,12 +1241,54 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class LongConstant : Constant { public readonly long Value; - public LongConstant (long v) + public LongConstant (long v, Location loc): + base (loc) { type = TypeManager.int64_type; eclass = ExprClass.Value; @@ -792,12 +1324,12 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () @@ -805,7 +1337,7 @@ namespace Mono.CSharp { if (Value < 0) return null; - return new ULongConstant ((ulong) Value); + return new ULongConstant ((ulong) Value, loc); } public override LongConstant ConvertToLong () @@ -822,7 +1354,18 @@ namespace Mono.CSharp { { return null; } + + public override Constant Increment () + { + return new LongConstant (checked(Value + 1), loc); + } + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return Value < 0; @@ -832,12 +1375,58 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (ec, Value, target_type, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (ec, Value, target_type, Int32.MinValue, Int32.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (ec, Value, target_type, UInt32.MinValue, UInt32.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + CheckUnsigned (ec, Value, target_type); + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MinValue, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class ULongConstant : Constant { public readonly ulong Value; - public ULongConstant (ulong v) + public ULongConstant (ulong v, Location loc): + base (loc) { type = TypeManager.uint64_type; eclass = ExprClass.Value; @@ -863,12 +1452,12 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () { - return new FloatConstant (Value); + return new FloatConstant (Value, loc); } public override ULongConstant ConvertToULong () @@ -891,6 +1480,17 @@ namespace Mono.CSharp { return null; } + public override Constant Increment () + { + return new ULongConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return false; @@ -900,12 +1500,58 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return Value == 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, (ulong) SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (ec, Value, target_type, (ulong) Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (ec, Value, target_type, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (ec, Value, target_type, Int32.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (ec, Value, target_type, UInt32.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + CheckRange (ec, Value, target_type, (ulong) Int64.MaxValue); + return new LongConstant ((long) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, Char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class FloatConstant : Constant { public readonly float Value; - public FloatConstant (float v) + public FloatConstant (float v, Location loc): + base (loc) { type = TypeManager.float_type; eclass = ExprClass.Value; @@ -929,7 +1575,7 @@ namespace Mono.CSharp { public override DoubleConstant ConvertToDouble () { - return new DoubleConstant (Value); + return new DoubleConstant (Value, loc); } public override FloatConstant ConvertToFloat () @@ -952,17 +1598,58 @@ namespace Mono.CSharp { return null; } + public override Constant Increment () + { + return new FloatConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return Value < 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) + return new ByteConstant ((byte) Value, Location); + if (target_type == TypeManager.sbyte_type) + return new SByteConstant ((sbyte) Value, Location); + if (target_type == TypeManager.short_type) + return new ShortConstant ((short) Value, Location); + if (target_type == TypeManager.ushort_type) + return new UShortConstant ((ushort) Value, Location); + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint) Value, Location); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) + return new CharConstant ((char) Value, Location); + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class DoubleConstant : Constant { public readonly double Value; - public DoubleConstant (double v) + public DoubleConstant (double v, Location loc): + base (loc) { type = TypeManager.double_type; eclass = ExprClass.Value; @@ -1014,17 +1701,64 @@ namespace Mono.CSharp { return null; } + public override Constant Increment () + { + return new DoubleConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return Value < 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (ec, Value, target_type, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (ec, Value, target_type, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) + return new ShortConstant ((short) Value, Location); + if (target_type == TypeManager.ushort_type) + return new UShortConstant ((ushort) Value, Location); + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint) Value, Location); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong) Value, Location); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (ec, Value, target_type, char.MinValue, char.MaxValue); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + } public class DecimalConstant : Constant { public readonly decimal Value; - public DecimalConstant (decimal d) + public DecimalConstant (decimal d, Location loc): + base (loc) { type = TypeManager.decimal_type; eclass = ExprClass.Value; @@ -1043,15 +1777,24 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { + ILGenerator ig = ec.ig; + int [] words = Decimal.GetBits (Value); + int power = (words [3] >> 16) & 0xff; + + if (power == 0 && Value <= int.MaxValue && Value >= int.MinValue) + { + IntConstant.EmitInt (ig, (int)Value); + ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg); + return; + } + // // FIXME: we could optimize this, and call a better // constructor // - ILGenerator ig = ec.ig; - IntConstant.EmitInt (ig, words [0]); IntConstant.EmitInt (ig, words [1]); IntConstant.EmitInt (ig, words [2]); @@ -1060,22 +1803,63 @@ namespace Mono.CSharp { IntConstant.EmitInt (ig, words [3] >> 31); // power - IntConstant.EmitInt (ig, (words [3] >> 16) & 0xff); + IntConstant.EmitInt (ig, power); ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args); } + public override Constant Increment () + { + return new DecimalConstant (checked (Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + public override bool IsNegative { get { return Value < 0; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + if (target_type == TypeManager.sbyte_type) + return new SByteConstant ((sbyte)Value, loc); + if (target_type == TypeManager.byte_type) + return new ByteConstant ((byte)Value, loc); + if (target_type == TypeManager.short_type) + return new ShortConstant ((short)Value, loc); + if (target_type == TypeManager.ushort_type) + return new UShortConstant ((ushort)Value, loc); + if (target_type == TypeManager.int32_type) + return new IntConstant ((int)Value, loc); + if (target_type == TypeManager.uint32_type) + return new UIntConstant ((uint)Value, loc); + if (target_type == TypeManager.int64_type) + return new LongConstant ((long)Value, loc); + if (target_type == TypeManager.uint64_type) + return new ULongConstant ((ulong)Value, loc); + if (target_type == TypeManager.char_type) + return new CharConstant ((char)Value, loc); + if (target_type == TypeManager.float_type) + return new FloatConstant ((float)Value, loc); + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double)Value, loc); + + return null; + } + } public class StringConstant : Constant { public readonly string Value; - public StringConstant (string s) + public StringConstant (string s, Location loc): + base (loc) { type = TypeManager.string_type; eclass = ExprClass.Value; @@ -1101,11 +1885,27 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Ldstr, Value); } + public override Constant Increment () + { + throw new NotSupportedException (); + } + + public override bool IsDefaultValue { + get { + return Value == null; + } + } + public override bool IsNegative { get { return false; } } + + public override Constant Reduce (EmitContext ec, Type target_type) + { + return null; + } } }