X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconstant.cs;h=8ea18f3c74d842f9d4d26334ac75c89826222d9d;hb=bc5aebde4188af99f1b3d5415be88910e436f209;hp=6fa4c625233b07cde9734a7b8a25a7fd6fd55e31;hpb=7986ed58a316804b785ea30e92db3a26bf3940b0;p=mono.git diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs old mode 100755 new mode 100644 index 6fa4c625233..8ea18f3c74d --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -3,6 +3,7 @@ // // Author: // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@seznam.cz) // // (C) 2001 Ximian, Inc. // @@ -18,9 +19,9 @@ namespace Mono.CSharp { /// public abstract class Constant : Expression { - protected Constant () + protected Constant (Location loc) { - eclass = ExprClass.Value; + this.loc = loc; } /// @@ -35,7 +36,19 @@ namespace Mono.CSharp { override public string ToString () { - return AsString (); + return this.GetType ().Name + " (" + AsString () + ")"; + } + + public override bool GetAttributableValue (Type valueType, out object value) + { + Constant c = ImplicitConversionRequired (valueType, loc); + if (c == null) { + value = null; + return false; + } + + value = c.GetTypedValue (); + return true; } /// @@ -44,6 +57,11 @@ namespace Mono.CSharp { /// public abstract object GetValue (); + public virtual object GetTypedValue () + { + return GetValue (); + } + /// /// Constants are always born in a fully resolved state /// @@ -51,14 +69,347 @@ namespace Mono.CSharp { { return this; } + + public Constant ImplicitConversionRequired (Type type, Location loc) + { + Constant c = ToType (type); + if (c == null) + Error_ValueCannotBeConverted (loc, type, false); + return c; + } + + // + // The various ToXXXX conversion functions are used by the constant + // folding evaluator. A null value is returned if the conversion is + // not possible. + // + // Note: not all the patterns for catching `implicit_conv' are the same. + // some implicit conversions can never be performed between two types + // even if the conversion would be lossless (for example short to uint), + // but some conversions are explicitly permitted by the standard provided + // that there will be no loss of information (for example, int to uint). + // + public DoubleConstant ToDouble (Location loc) + { + DoubleConstant c = ConvertToDouble (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.double_type, false); + + return c; + } + + public FloatConstant ToFloat (Location loc) + { + FloatConstant c = ConvertToFloat (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.float_type, false); + + return c; + } + + public ULongConstant ToULong (Location loc) + { + ULongConstant c = ConvertToULong (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.uint64_type, false); + + return c; + } + + public LongConstant ToLong (Location loc) + { + LongConstant c = ConvertToLong (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.int64_type, false); + + return c; + } + + public UIntConstant ToUInt (Location loc) + { + UIntConstant c = ConvertToUInt (); + + if (c == null) + Error_ValueCannotBeConverted (loc, TypeManager.uint32_type, false); + + return c; + } + + public IntConstant ToInt (Location loc) + { + IntConstant c = ConvertToInt (); + + if (c == null) + 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) + { + if (Type == type) + return this; + + if (type == TypeManager.object_type) + return this; + + if (!Convert.ImplicitStandardConversionExists (this, type)){ + 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){ + // + // 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)); + } + + return CreateConstant (type, constant_value, loc); + } + + /// Returns a constant instance based on Type + /// The returned value is already resolved. + public static Constant CreateConstant (Type t, object v, Location loc) + { + if (t == TypeManager.int32_type) + return new IntConstant ((int) v, loc); + if (t == TypeManager.string_type) + return new StringConstant ((string) v, loc); + if (t == TypeManager.uint32_type) + return new UIntConstant ((uint) v, loc); + if (t == TypeManager.int64_type) + return new LongConstant ((long) v, loc); + if (t == TypeManager.uint64_type) + return new ULongConstant ((ulong) v, loc); + if (t == TypeManager.float_type) + return new FloatConstant ((float) v, loc); + if (t == TypeManager.double_type) + return new DoubleConstant ((double) v, loc); + if (t == TypeManager.short_type) + return new ShortConstant ((short)v, loc); + if (t == TypeManager.ushort_type) + return new UShortConstant ((ushort)v, loc); + if (t == TypeManager.sbyte_type) + return new SByteConstant ((sbyte)v, loc); + if (t == TypeManager.byte_type) + return new ByteConstant ((byte)v, loc); + if (t == TypeManager.char_type) + return new CharConstant ((char)v, loc); + if (t == TypeManager.bool_type) + return new BoolConstant ((bool) v, loc); + if (t == TypeManager.decimal_type) + return new DecimalConstant ((decimal) v, loc); + if (TypeManager.IsEnumType (t)) { + Type real_type = TypeManager.TypeToCoreType (v.GetType ()); + if (real_type == t) + real_type = System.Enum.GetUnderlyingType (real_type); + return new EnumConstant (CreateConstant (real_type, v, loc), t); + } + if (v == null && !TypeManager.IsValueType (t)) + return new EmptyConstantCast (new NullConstant (loc), t); + + throw new Exception ("Unknown type for constant (" + t + + "), details: " + v); + } + + protected static void CheckRange (bool inCheckedContext, ulong value, ulong max) + { + if (!inCheckedContext) + return; + + if (value > max) + throw new OverflowException (); + } + + protected static void CheckRange (bool inCheckedContext, double value, long min, long max) + { + if (!inCheckedContext) + return; + + if (((value < min) || (value > max))) + throw new OverflowException (); + + if (double.IsNaN (value)) + throw new OverflowException (); + } + + protected static void CheckRange (bool inCheckedContext, double value, ulong min, ulong max) + { + if (!inCheckedContext) + return; + + if (((value < min) || (value > max))) + throw new OverflowException (); + + if (double.IsNaN (value)) + throw new OverflowException (); + } + + protected static void CheckUnsigned (bool inCheckedContext, long value) + { + if (!inCheckedContext) + return; + + if (value < 0) + throw new OverflowException (); + } + + /// + /// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type. + /// It throws OverflowException + /// + public abstract Constant Reduce (bool inCheckedContext, 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) { + Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", + GetValue ().ToString (), TypeManager.CSharpName (target_type)); + throw; + } + } + + 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.ConstantCheckState, target_type); + } + + + public virtual DecimalConstant ConvertToDecimal () + { + return null; + } + + public virtual DoubleConstant ConvertToDouble () + { + return null; + } + + public virtual FloatConstant ConvertToFloat () + { + return null; + } + + public virtual ULongConstant ConvertToULong () + { + return null; + } + + public virtual LongConstant ConvertToLong () + { + return null; + } + + public virtual UIntConstant ConvertToUInt () + { + return null; + } + + public virtual IntConstant ConvertToInt () + { + return null; + } + + public abstract Constant Increment (); + + /// + /// Need to pass type as the constant can require a boxing + /// and in such case no optimization is possible + /// + public bool IsDefaultInitializer (Type type) + { + if (type == Type) + return IsDefaultValue; + + return Type == TypeManager.null_type; + } + + public abstract bool IsDefaultValue { + get; + } + + public abstract bool IsNegative { + get; + } + + // + // Returns true iff 1) the stack type of this is one of Object, + // int32, int64 and 2) this == 0 or this == null. + // + public virtual bool IsZeroInteger { + get { return false; } + } } + public abstract class IntegralConstant : Constant { + protected IntegralConstant (Location loc) : + base (loc) + { + } + + public override void Error_ValueCannotBeConverted (Location loc, Type target, bool expl) + { + try { + Reduce (true, target); + base.Error_ValueCannotBeConverted (loc, target, expl); + } + catch + { + Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", + GetValue ().ToString (), TypeManager.CSharpName (target)); + } + } + } + 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; Value = val; } @@ -81,14 +432,43 @@ 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; + } + } + + public override bool IsZeroInteger { + get { return Value == false; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + return null; + } + } - public class ByteConstant : Constant { + public class ByteConstant : IntegralConstant { public readonly byte Value; - public ByteConstant (byte v) + public ByteConstant (byte v, Location loc): + base (loc) { type = TypeManager.byte_type; + eclass = ExprClass.Value; Value = v; } @@ -106,14 +486,98 @@ namespace Mono.CSharp { { return Value; } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + return new ULongConstant (Value, loc); + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return new UIntConstant (Value, loc); + } + + public override IntConstant ConvertToInt () + { + 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; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, 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; Value = v; } @@ -151,54 +615,906 @@ namespace Mono.CSharp { return c.ToString (); } - public override string AsString () + public override string AsString () + { + return "\"" + descape (Value) + "\""; + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + return new ULongConstant (Value, loc); + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return new UIntConstant (Value, loc); + } + + public override IntConstant ConvertToInt () + { + 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; + } + } + + public override bool IsZeroInteger { + get { return Value == '\0'; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, 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 : IntegralConstant { + public readonly sbyte Value; + + public SByteConstant (sbyte v, Location loc): + base (loc) + { + type = TypeManager.sbyte_type; + eclass = ExprClass.Value; + Value = v; + } + + public override void Emit (EmitContext ec) + { + IntLiteral.EmitInt (ec.ig, Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + if (Value >= 0) + return new ULongConstant ((ulong) Value, loc); + + return null; + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return null; + } + + public override IntConstant ConvertToInt () + { + 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; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckUnsigned (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + + } + + public class ShortConstant : IntegralConstant { + public readonly short Value; + + public ShortConstant (short v, Location loc): + base (loc) + { + type = TypeManager.short_type; + eclass = ExprClass.Value; + Value = v; + } + + public override void Emit (EmitContext ec) + { + IntLiteral.EmitInt (ec.ig, Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + return null; + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return null; + } + + public override IntConstant ConvertToInt () + { + 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 { + get { return Value == 0; } + } + + public override bool IsNegative { + get { + return Value < 0; + } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckUnsigned (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value); + 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 (inCheckedContext, Value, 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 : IntegralConstant { + public readonly ushort Value; + + public UShortConstant (ushort v, Location loc): + base (loc) + { + type = TypeManager.ushort_type; + eclass = ExprClass.Value; + Value = v; + } + + public override void Emit (EmitContext ec) + { + IntLiteral.EmitInt (ec.ig, Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + return new ULongConstant (Value, loc); + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return new UIntConstant (Value, loc); + } + + public override IntConstant ConvertToInt () + { + 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; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 : IntegralConstant { + public readonly int Value; + + public IntConstant (int v, Location loc): + base (loc) + { + type = TypeManager.int32_type; + eclass = ExprClass.Value; + Value = v; + } + + static public void EmitInt (ILGenerator ig, int i) + { + switch (i){ + case -1: + ig.Emit (OpCodes.Ldc_I4_M1); + break; + + case 0: + ig.Emit (OpCodes.Ldc_I4_0); + break; + + case 1: + ig.Emit (OpCodes.Ldc_I4_1); + break; + + case 2: + ig.Emit (OpCodes.Ldc_I4_2); + break; + + case 3: + ig.Emit (OpCodes.Ldc_I4_3); + break; + + case 4: + ig.Emit (OpCodes.Ldc_I4_4); + break; + + case 5: + ig.Emit (OpCodes.Ldc_I4_5); + break; + + case 6: + ig.Emit (OpCodes.Ldc_I4_6); + break; + + case 7: + ig.Emit (OpCodes.Ldc_I4_7); + break; + + case 8: + ig.Emit (OpCodes.Ldc_I4_8); + break; + + default: + if (i >= -128 && i <= 127){ + ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i); + } else + ig.Emit (OpCodes.Ldc_I4, i); + break; + } + } + + public override void Emit (EmitContext ec) + { + EmitInt (ec.ig, Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DecimalConstant ConvertToDecimal() + { + return new DecimalConstant (Value, loc); + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + if (Value < 0) + return null; + + return new ULongConstant ((ulong) Value, loc); + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + if (Value < 0) + return null; + + 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 { + return Value < 0; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (inCheckedContext, Value, UInt32.MinValue, UInt32.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 (inCheckedContext, Value); + 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 (inCheckedContext, Value, 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 : IntegralConstant { + public readonly uint Value; + + public UIntConstant (uint v, Location loc): + base (loc) + { + type = TypeManager.uint32_type; + eclass = ExprClass.Value; + Value = v; + } + + public override void Emit (EmitContext ec) + { + IntLiteral.EmitInt (ec.ig, unchecked ((int) Value)); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () + { + return new FloatConstant (Value, loc); + } + + public override ULongConstant ConvertToULong () + { + return new ULongConstant (Value, loc); + } + + public override LongConstant ConvertToLong () + { + return new LongConstant (Value, loc); + } + + public override UIntConstant ConvertToUInt () + { + return this; + } + + public override IntConstant ConvertToInt () + { + 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; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) + { + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Char.MinValue, Char.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (inCheckedContext, Value, 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 (inCheckedContext, Value, 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 : IntegralConstant { + public readonly long Value; + + public LongConstant (long v, Location loc): + base (loc) + { + type = TypeManager.int64_type; + eclass = ExprClass.Value; + Value = v; + } + + public override void Emit (EmitContext ec) + { + EmitLong (ec.ig, Value); + } + + static public void EmitLong (ILGenerator ig, long l) + { + if (l >= int.MinValue && l <= int.MaxValue) { + IntLiteral.EmitInt (ig, unchecked ((int) l)); + ig.Emit (OpCodes.Conv_I8); + return; + } + ig.Emit (OpCodes.Ldc_I8, l); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } + + public override FloatConstant ConvertToFloat () { - return "\"" + descape (Value) + "\""; + return new FloatConstant (Value, loc); } - public override object GetValue () + public override ULongConstant ConvertToULong () { - return Value; + if (Value < 0) + return null; + + return new ULongConstant ((ulong) Value, loc); } - } - public class SByteConstant : Constant { - public readonly sbyte Value; + public override LongConstant ConvertToLong () + { + return this; + } - public SByteConstant (sbyte v) + public override UIntConstant ConvertToUInt () { - type = TypeManager.sbyte_type; - Value = v; + return null; } - public override void Emit (EmitContext ec) + public override IntConstant ConvertToInt () { - IntLiteral.EmitInt (ec.ig, Value); + return null; } - public override string AsString () + public override Constant Increment () { - return Value.ToString (); + return new LongConstant (checked(Value + 1), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } } - public override object GetValue () + public override bool IsNegative { + get { + return Value < 0; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) { - return Value; + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, Int16.MinValue, Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, UInt16.MinValue, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (inCheckedContext, Value, Int32.MinValue, Int32.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (inCheckedContext, Value, UInt32.MinValue, UInt32.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + CheckUnsigned (inCheckedContext, Value); + 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 (inCheckedContext, Value, 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 ShortConstant : Constant { - public readonly short Value; + public class ULongConstant : IntegralConstant { + public readonly ulong Value; - public ShortConstant (short v) + public ULongConstant (ulong v, Location loc): + base (loc) { - type = TypeManager.short_type; + type = TypeManager.uint64_type; + eclass = ExprClass.Value; Value = v; } public override void Emit (EmitContext ec) { - IntLiteral.EmitInt (ec.ig, Value); + ILGenerator ig = ec.ig; + + LongLiteral.EmitLong (ig, unchecked ((long) Value)); } public override string AsString () @@ -210,122 +1526,118 @@ namespace Mono.CSharp { { return Value; } - } - - public class UShortConstant : Constant { - public readonly ushort Value; - public UShortConstant (ushort v) + public override DoubleConstant ConvertToDouble () { - type = TypeManager.ushort_type; - Value = v; + return new DoubleConstant (Value, loc); } - public override void Emit (EmitContext ec) + public override FloatConstant ConvertToFloat () { - IntLiteral.EmitInt (ec.ig, Value); + return new FloatConstant (Value, loc); } - public override string AsString () + public override ULongConstant ConvertToULong () { - return Value.ToString (); + return this; } - public override object GetValue () + public override LongConstant ConvertToLong () { - return Value; + return null; } - } - public class IntConstant : Constant { - public readonly int Value; + public override UIntConstant ConvertToUInt () + { + return null; + } - public IntConstant (int v) + public override IntConstant ConvertToInt () { - type = TypeManager.int32_type; - Value = v; + return null; } - static public void EmitInt (ILGenerator ig, int i) + public override Constant Increment () { - switch (i){ - case -1: - ig.Emit (OpCodes.Ldc_I4_M1); - break; - - case 0: - ig.Emit (OpCodes.Ldc_I4_0); - break; - - case 1: - ig.Emit (OpCodes.Ldc_I4_1); - break; - - case 2: - ig.Emit (OpCodes.Ldc_I4_2); - break; - - case 3: - ig.Emit (OpCodes.Ldc_I4_3); - break; - - case 4: - ig.Emit (OpCodes.Ldc_I4_4); - break; - - case 5: - ig.Emit (OpCodes.Ldc_I4_5); - break; - - case 6: - ig.Emit (OpCodes.Ldc_I4_6); - break; - - case 7: - ig.Emit (OpCodes.Ldc_I4_7); - break; - - case 8: - ig.Emit (OpCodes.Ldc_I4_8); - break; + return new ULongConstant (checked(Value + 1), loc); + } - default: - if (i >= -128 && i <= 127){ - ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i); - } else - ig.Emit (OpCodes.Ldc_I4, i); - break; + public override bool IsDefaultValue { + get { + return Value == 0; } } - public override void Emit (EmitContext ec) - { - EmitInt (ec.ig, Value); + public override bool IsNegative { + get { + return false; + } } - public override string AsString () - { - return Value.ToString (); + public override bool IsZeroInteger { + get { return Value == 0; } } - public override object GetValue () + public override Constant Reduce (bool inCheckedContext, Type target_type) { - return Value; + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, (ulong) SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, (ulong) Int16.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, UInt16.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (inCheckedContext, Value, Int32.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (inCheckedContext, Value, UInt32.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + CheckRange (inCheckedContext, Value, (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 (inCheckedContext, Value, 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 class FloatConstant : Constant { + public float Value; - public UIntConstant (uint v) + public FloatConstant (float v, Location loc): + base (loc) { - type = TypeManager.uint32_type; + type = TypeManager.float_type; + eclass = ExprClass.Value; Value = v; } public override void Emit (EmitContext ec) { - IntLiteral.EmitInt (ec.ig, unchecked ((int) Value)); + ec.ig.Emit (OpCodes.Ldc_R4, Value); } public override string AsString () @@ -337,54 +1649,111 @@ namespace Mono.CSharp { { return Value; } - } - public class LongConstant : Constant { - public readonly long Value; + public override DoubleConstant ConvertToDouble () + { + return new DoubleConstant (Value, loc); + } - public LongConstant (long v) + public override FloatConstant ConvertToFloat () { - type = TypeManager.int64_type; - Value = v; + return this; } - public override void Emit (EmitContext ec) + public override LongConstant ConvertToLong () { - ILGenerator ig = ec.ig; + return null; + } - EmitLong (ig, Value); + public override UIntConstant ConvertToUInt () + { + return null; } - static public void EmitLong (ILGenerator ig, long l) + public override IntConstant ConvertToInt () { - ig.Emit (OpCodes.Ldc_I8, l); + return null; } - public override string AsString () + public override Constant Increment () { - return Value.ToString (); + return new FloatConstant (checked(Value + 1), loc); } - public override object GetValue () + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + + public override bool IsNegative { + get { + return Value < 0; + } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) { - return Value; + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, byte.MinValue, byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, sbyte.MinValue, sbyte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue); + return new LongConstant ((long) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue); + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + CheckRange (inCheckedContext, Value, 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 class DoubleConstant : Constant { + public double Value; - public ULongConstant (ulong v) + public DoubleConstant (double v, Location loc): + base (loc) { - type = TypeManager.uint64_type; + type = TypeManager.double_type; + eclass = ExprClass.Value; Value = v; } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - LongLiteral.EmitLong (ig, unchecked ((long) Value)); + ec.ig.Emit (OpCodes.Ldc_R8, Value); } public override string AsString () @@ -396,64 +1765,110 @@ namespace Mono.CSharp { { return Value; } - } - public class FloatConstant : Constant { - public readonly float Value; - - public FloatConstant (float v) + public override DoubleConstant ConvertToDouble () { - type = TypeManager.float_type; - Value = v; + return this; } - public override void Emit (EmitContext ec) + public override FloatConstant ConvertToFloat () { - ec.ig.Emit (OpCodes.Ldc_R4, Value); + return null; } - public override string AsString () + public override ULongConstant ConvertToULong () { - return Value.ToString (); + return null; } - public override object GetValue () + public override LongConstant ConvertToLong () { - return Value; + return null; } - } - public class DoubleConstant : Constant { - public readonly double Value; - - public DoubleConstant (double v) + public override UIntConstant ConvertToUInt () { - type = TypeManager.double_type; - Value = v; + return null; } - public override void Emit (EmitContext ec) + public override IntConstant ConvertToInt () { - ec.ig.Emit (OpCodes.Ldc_R8, Value); + return null; } - public override string AsString () + public override Constant Increment () { - return Value.ToString (); + return new DoubleConstant (checked(Value + 1), loc); } - public override object GetValue () + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + + public override bool IsNegative { + get { + return Value < 0; + } + } + + public override Constant Reduce (bool inCheckedContext, Type target_type) { - return Value; + if (target_type == TypeManager.byte_type) { + CheckRange (inCheckedContext, Value, Byte.MinValue, Byte.MaxValue); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + CheckRange (inCheckedContext, Value, SByte.MinValue, SByte.MaxValue); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + CheckRange (inCheckedContext, Value, short.MinValue, short.MaxValue); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + CheckRange (inCheckedContext, Value, ushort.MinValue, ushort.MaxValue); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + CheckRange (inCheckedContext, Value, int.MinValue, int.MaxValue); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + CheckRange (inCheckedContext, Value, uint.MinValue, uint.MaxValue); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + CheckRange (inCheckedContext, Value, long.MinValue, long.MaxValue); + return new LongConstant ((long) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + CheckRange (inCheckedContext, Value, ulong.MinValue, ulong.MaxValue); + 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 (inCheckedContext, Value, 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; Value = d; } @@ -469,16 +1884,92 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - throw new Exception ("Implement me"); + 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 + // + + IntConstant.EmitInt (ig, words [0]); + IntConstant.EmitInt (ig, words [1]); + IntConstant.EmitInt (ig, words [2]); + + // sign + IntConstant.EmitInt (ig, words [3] >> 31); + + // power + 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 (bool inCheckedContext, 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; Value = s; } @@ -495,7 +1986,32 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - ec.ig.Emit (OpCodes.Ldstr, Value); + if (Value == null) + ec.ig.Emit (OpCodes.Ldnull); + else + 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 (bool inCheckedContext, Type target_type) + { + return null; } }