X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconstant.cs;h=c04ad0246df1417ee4d111d3245a9f5e4e2370c1;hb=7674f7142c1f8e30c32d8559d56f3bfc91387ea0;hp=536b0878583e23d133042df6bb34efebf41ba5fc;hpb=e2fdf31a2a565184dabf235a75dc8ab184fea4f2;p=mono.git diff --git a/mcs/mcs/constant.cs b/mcs/mcs/constant.cs old mode 100755 new mode 100644 index 536b0878583..c04ad0246df --- a/mcs/mcs/constant.cs +++ b/mcs/mcs/constant.cs @@ -1,139 +1,2130 @@ // -// constant.cs: Constant expressions and constant folding. +// constant.cs: Constants. // // Author: // Miguel de Icaza (miguel@ximian.com) +// Marek Safar (marek.safar@seznam.cz) // -// (C) 2001 Ximian, Inc. -// +// Copyright 2001-2003 Ximian, Inc. +// Copyright 2003-2008 Novell, Inc. // -namespace Mono.CSharp { +using System; +using System.Reflection.Emit; + +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, + /// and is not guaranteed to be useful for anything else, + /// AsString() will provide something that can be used + /// for round-tripping C# code. Maybe it can be used + /// for IL assembly as well. + /// + public abstract string AsString (); + + override public string ToString () + { + return this.GetType ().Name + " (" + AsString () + ")"; + } + + /// + /// This is used to obtain the actual value of the literal + /// cast into an object. + /// + public abstract object GetValue (); + + public virtual object GetTypedValue () + { + return GetValue (); + } + + public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) + { + if (!expl && IsLiteral && + (TypeManager.IsPrimitiveType (target) || type == TypeManager.decimal_type) && + (TypeManager.IsPrimitiveType (type) || type == TypeManager.decimal_type)) { + ec.Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", + AsString (), TypeManager.CSharpName (target)); + } else { + base.Error_ValueCannotBeConverted (ec, loc, target, expl); + } + } + + public Constant ImplicitConversionRequired (ResolveContext ec, TypeSpec type, Location loc) + { + Constant c = ConvertImplicitly (ec, type); + if (c == null) + Error_ValueCannotBeConverted (ec, loc, type, false); + + return c; + } + + public virtual Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) + { + if (this.type == type) + return this; + + if (Convert.ImplicitNumericConversion (this, type) == null) + return null; + + 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 InternalErrorException ("Missing constant conversion between `{0}' and `{1}'", + TypeManager.CSharpName (Type), TypeManager.CSharpName (type)); + } + + return CreateConstant (rc, type, constant_value, loc); + } + + // + // Returns a constant instance based on Type + // + public static Constant CreateConstant (ResolveContext rc, TypeSpec t, object v, Location loc) + { + return CreateConstantFromValue (t, v, loc).Resolve (rc); + } + + public static Constant CreateConstantFromValue (TypeSpec 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)) { + var real_type = EnumSpec.GetUnderlyingType (t); + return new EnumConstant (CreateConstantFromValue (real_type, v, loc).Resolve (null), t); + } + if (v == null) { + if (TypeManager.IsNullableType (t)) + return Nullable.LiftedNull.Create (t, loc); + + if (TypeManager.IsReferenceType (t)) + return new NullConstant (t, loc); + } + + throw new InternalErrorException ("Constant value `{0}' has unexpected underlying type `{1}'", + v, TypeManager.CSharpName (t)); + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + Arguments args = new Arguments (2); + args.Add (new Argument (this)); + args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); + + return CreateExpressionFactoryCall (ec, "Constant", args); + } + + + /// + /// Maybe ConvertTo name is better. It tries to convert `this' constant to target_type. + /// It throws OverflowException + /// + // DON'T CALL THIS METHOD DIRECTLY AS IT DOES NOT HANDLE ENUMS + public abstract Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type); + + /// + /// Attempts to do a compile-time folding of a constant cast. + /// + public Constant TryReduce (ResolveContext ec, TypeSpec target_type, Location loc) + { + try { + return TryReduce (ec, target_type); + } + catch (OverflowException) { + if (ec.ConstantCheckState) { + ec.Report.Error (221, loc, "Constant value `{0}' cannot be converted to a `{1}' (use `unchecked' syntax to override)", + GetValue ().ToString (), TypeManager.CSharpName (target_type)); + } else { + Error_ValueCannotBeConverted (ec, loc, target_type, false); + } + + return New.Constantify (target_type).Resolve (ec); + } + } + + Constant TryReduce (ResolveContext ec, TypeSpec target_type) + { + if (Type == target_type) + return this; + + Constant c; + if (TypeManager.IsEnumType (target_type)) { + c = TryReduce (ec, EnumSpec.GetUnderlyingType (target_type)); + if (c == null) + return null; + + return new EnumConstant (c, target_type).Resolve (ec); + } + + c = ConvertExplicitly (ec.ConstantCheckState, target_type); + if (c != null) + c = c.Resolve (ec); + + return c; + } + + /// + /// Need to pass type as the constant can require a boxing + /// and in such case no optimization is possible + /// + public bool IsDefaultInitializer (TypeSpec type) + { + if (type == Type) + return IsDefaultValue; + + return this is NullLiteral; + } + + public abstract bool IsDefaultValue { + get; + } + + public abstract bool IsNegative { + get; + } + + // + // When constant is declared as literal + // + public virtual bool IsLiteral { + get { return false; } + } + + public virtual bool IsOneInteger { + get { return false; } + } + + // + // 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 override void EmitSideEffect (EmitContext ec) + { + // do nothing + } + + protected override void CloneTo (CloneContext clonectx, Expression target) + { + // CloneTo: Nothing, we do not keep any state on this expression + } + + public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx) + { + return System.Linq.Expressions.Expression.Constant (GetTypedValue (), type.GetMetaInfo ()); + } + + public new Constant Resolve (ResolveContext rc) + { + if (eclass != ExprClass.Unresolved) + return this; + + // Resolved constant has to be still a constant + Constant c = (Constant) DoResolve (rc); + if (c == null) + return null; + + if ((c.eclass & ExprClass.Value) == 0) { + c.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc); + return null; + } + + if (c.type == null) + throw new InternalErrorException ("Expression `{0}' did not set its type after Resolve", c.GetType ()); + + return c; + } + } + + public abstract class IntegralConstant : Constant { + protected IntegralConstant (Location loc) : + base (loc) + { + } + + public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl) + { + try { + ConvertExplicitly (true, target); + base.Error_ValueCannotBeConverted (ec, loc, target, expl); + } + catch + { + ec.Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", + GetValue ().ToString (), TypeManager.CSharpName (target)); + } + } + + public abstract Constant Increment (); + } + + public class BoolConstant : Constant { + public readonly bool Value; + + public BoolConstant (bool val, Location loc): + base (loc) + { + Value = val; + } + + override public string AsString () + { + return Value ? "true" : "false"; + } + + protected override Expression DoResolve (ResolveContext ec) + { + type = TypeManager.bool_type; + eclass = ExprClass.Value; + return this; + } + + public override object GetValue () + { + return (object) Value; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + if (Value) + ec.Emit (OpCodes.Ldc_I4_1); + else + ec.Emit (OpCodes.Ldc_I4_0); + } + + 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 ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + return null; + } + + } + + public class ByteConstant : IntegralConstant { + public readonly byte Value; + + public ByteConstant (byte v, Location loc): + base (loc) + { + Value = v; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + protected override Expression DoResolve (ResolveContext ec) + { + type = TypeManager.byte_type; + eclass = ExprClass.Value; + return this; + } + + public override object GetValue () + { + return Value; + } + + public override Constant Increment () + { + return new ByteConstant (checked ((byte)(Value + 1)), loc); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsNegative { + get { + return false; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } + 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, Location loc): + base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.char_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write ((ushort) Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + static string descape (char c) + { + switch (c){ + case '\a': + return "\\a"; + case '\b': + return "\\b"; + case '\n': + return "\\n"; + case '\t': + return "\\t"; + case '\v': + return "\\v"; + case '\r': + return "\\r"; + case '\\': + return "\\\\"; + case '\f': + return "\\f"; + case '\0': + return "\\0"; + case '"': + return "\\\""; + case '\'': + return "\\\'"; + } + return c.ToString (); + } + + public override string AsString () + { + return "\"" + descape (Value) + "\""; + } + + public override object GetValue () + { + return Value; + } + + 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 ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } + 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) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.sbyte_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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 IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.short_type) + return new ShortConstant ((short) Value, Location); + if (target_type == TypeManager.ushort_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + return new UShortConstant ((ushort) Value, Location); + } if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + return new UIntConstant ((uint) Value, Location); + } if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + 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) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + 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) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.short_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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 bool IsOneInteger { + get { + return Value == 1; + } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) + return new IntConstant ((int) Value, Location); + if (target_type == TypeManager.uint32_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + 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) { + if (in_checked_context){ + if (Value < Char.MinValue) + throw new OverflowException (); + } + 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) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.ushort_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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 IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value > Byte.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } + 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) { + if (in_checked_context){ + if (Value > Char.MaxValue) + throw new OverflowException (); + } + 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) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.int32_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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 IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < Int16.MinValue || Value > Int16.MaxValue) + throw new OverflowException (); + } + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < UInt32.MinValue) + throw new OverflowException (); + } + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) + return new LongConstant ((long) Value, Location); + if (target_type == TypeManager.uint64_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + 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) { + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) + { + if (this.type == type) + return this; + + Constant c = TryImplicitIntConversion (type); + if (c != null) + return c.Resolve (rc); + + return base.ConvertImplicitly (rc, type); + } + + /// + /// Attempts to perform an implicit constant conversion of the IntConstant + /// into a different data type using casts (See Implicit Constant + /// Expression Conversions) + /// + Constant TryImplicitIntConversion (TypeSpec target_type) + { + if (target_type == TypeManager.sbyte_type) { + if (Value >= SByte.MinValue && Value <= SByte.MaxValue) + return new SByteConstant ((sbyte) Value, loc); + } + else if (target_type == TypeManager.byte_type) { + if (Value >= Byte.MinValue && Value <= Byte.MaxValue) + return new ByteConstant ((byte) Value, loc); + } + else if (target_type == TypeManager.short_type) { + if (Value >= Int16.MinValue && Value <= Int16.MaxValue) + return new ShortConstant ((short) Value, loc); + } + else if (target_type == TypeManager.ushort_type) { + if (Value >= UInt16.MinValue && Value <= UInt16.MaxValue) + return new UShortConstant ((ushort) Value, loc); + } + else if (target_type == TypeManager.uint32_type) { + if (Value >= 0) + return new UIntConstant ((uint) Value, loc); + } + else if (target_type == TypeManager.uint64_type) { + // + // we can optimize this case: a positive int32 + // always fits on a uint64. But we need an opcode + // to do it. + // + if (Value >= 0) + return new ULongConstant ((ulong) Value, loc); + } + else if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, loc); + else if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, loc); + + return null; + } + } + + public class UIntConstant : IntegralConstant { + public readonly uint Value; + + public UIntConstant (uint v, Location loc): + base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.uint32_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitInt (unchecked ((int) Value)); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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 IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value > Int16.MaxValue) + throw new OverflowException (); + } + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value > Int32.MaxValue) + throw new OverflowException (); + } + 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) { + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } + 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) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.int64_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitLong (Value); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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; + } + } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < Int16.MinValue || Value > Int16.MaxValue) + throw new OverflowException (); + } + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < UInt16.MinValue || Value > UInt16.MaxValue) + throw new OverflowException (); + } + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value < Int32.MinValue || Value > Int32.MaxValue) + throw new OverflowException (); + } + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < UInt32.MinValue || Value > UInt32.MaxValue) + throw new OverflowException (); + } + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + if (in_checked_context && Value < 0) + throw new OverflowException (); + 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) { + if (in_checked_context){ + if (Value < Char.MinValue || Value > Char.MaxValue) + throw new OverflowException (); + } + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); + + return null; + } + + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type) + { + if (Value >= 0 && type == TypeManager.uint64_type) { + return new ULongConstant ((ulong) Value, loc).Resolve (rc); + } + + return base.ConvertImplicitly (rc, type); + } + } + + public class ULongConstant : IntegralConstant { + public readonly ulong Value; + + public ULongConstant (ulong v, Location loc): + base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.uint64_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.EmitLong (unchecked ((long) Value)); + } + + public override string AsString () + { + return Value.ToString (); + } + + public override object GetValue () + { + return Value; + } + + 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; + } + } + + public override bool IsOneInteger { + get { + return Value == 1; + } + } + + public override bool IsZeroInteger { + get { return Value == 0; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context && Value > Byte.MaxValue) + throw new OverflowException (); + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context && Value > ((ulong) SByte.MaxValue)) + throw new OverflowException (); + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context && Value > ((ulong) Int16.MaxValue)) + throw new OverflowException (); + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context && Value > UInt16.MaxValue) + throw new OverflowException (); + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context && Value > UInt32.MaxValue) + throw new OverflowException (); + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context && Value > UInt32.MaxValue) + throw new OverflowException (); + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + if (in_checked_context && Value > Int64.MaxValue) + throw new OverflowException (); + 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) { + if (in_checked_context && Value > Char.MaxValue) + throw new OverflowException (); + return new CharConstant ((char) Value, Location); + } + if (target_type == TypeManager.decimal_type) + return new DecimalConstant ((decimal) Value, Location); - using System; - using System.Reflection; - using System.Reflection.Emit; - using System.Collections; + return null; + } + } - public class Constant : Expression { + public class FloatConstant : Constant { + public float Value; - public readonly string Name; - public readonly string ConstantType; - public Expression Expr; - public Attributes OptAttributes; - - int mod_flags; - Location Location; - public FieldBuilder FieldBuilder; + public FloatConstant (float v, Location loc): + base (loc) + { + Value = v; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.float_type; + eclass = ExprClass.Value; + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + + public override void Emit (EmitContext ec) + { + ec.Emit (OpCodes.Ldc_R4, Value); + } - public const int AllowedModifiers = - Modifiers.NEW | - Modifiers.PUBLIC | - Modifiers.PROTECTED | - Modifiers.INTERNAL | - Modifiers.PRIVATE; + public override string AsString () + { + return Value.ToString (); + } - public Constant (string constant_type, string name, Expression expr, int mod_flags, - Attributes attrs, Location loc) + public override object GetValue () { - this.ConstantType = constant_type; - this.Name = name; - this.Expr = expr; - this.mod_flags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PRIVATE); - this.Location = loc; - OptAttributes = attrs; + return Value; } - public FieldAttributes FieldAttr { + public override bool IsDefaultValue { get { - return FieldAttributes.Literal | FieldAttributes.Static | - Modifiers.FieldAttr (mod_flags) ; + return Value == 0; } } - public int ModFlags { + public override bool IsNegative { get { - return mod_flags; + return Value < 0; + } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < byte.MinValue || Value > byte.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < sbyte.MinValue || Value > sbyte.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < short.MinValue || Value > short.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < ushort.MinValue || Value > ushort.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value < int.MinValue || Value > int.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < uint.MinValue || Value > uint.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new UIntConstant ((uint) Value, Location); } + if (target_type == TypeManager.int64_type) { + if (in_checked_context){ + if (Value < long.MinValue || Value > long.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new LongConstant ((long) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) Value, Location); + if (target_type == TypeManager.char_type) { + if (in_checked_context){ + if (Value < (float) char.MinValue || Value > (float) char.MaxValue || float.IsNaN (Value)) + throw new OverflowException (); + } + 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 double Value; + + public DoubleConstant (double v, Location loc): + base (loc) + { + Value = v; } - public override Expression DoResolve (EmitContext ec) + protected override Expression DoResolve (ResolveContext rc) { - // FIXME: implement + type = TypeManager.double_type; + eclass = ExprClass.Value; return this; } + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + enc.Stream.Write (Value); + } + public override void Emit (EmitContext ec) { - throw new Exception ("Unimplemented"); + ec.Emit (OpCodes.Ldc_R8, Value); } - void WarningNotHiding (TypeContainer parent) + public override string AsString () { - Report.Warning ( - 109, Location, - "The member `" + parent.Name + "." + Name + "' does not hide an " + - "inherited member. The keyword new is not required"); + return Value.ToString (); } - - /// - /// Defines the constant in the @parent - /// - public void Define (TypeContainer parent) + + public override object GetValue () { - type = parent.LookupType (ConstantType, true); + return Value; + } - if (type == null) - return; - - if (!TypeManager.IsBuiltinType (type) && (!type.IsSubclassOf (TypeManager.enum_type))) { - Report.Error (-3, Location, "Constant type is not valid (only system types are allowed)"); - return; + public override bool IsDefaultValue { + get { + return Value == 0; } + } - Type ptype = parent.TypeBuilder.BaseType; + public override bool IsNegative { + get { + return Value < 0; + } + } - if (ptype != null) { - MemberInfo [] mi = TypeContainer.FindMembers (ptype, MemberTypes.Field, BindingFlags.Public, - Type.FilterName, Name); - - if (mi == null || mi.Length == 0) - if ((ModFlags & Modifiers.NEW) != 0) - WarningNotHiding (parent); + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + if (target_type == TypeManager.byte_type) { + if (in_checked_context){ + if (Value < Byte.MinValue || Value > Byte.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new ByteConstant ((byte) Value, Location); + } + if (target_type == TypeManager.sbyte_type) { + if (in_checked_context){ + if (Value < SByte.MinValue || Value > SByte.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new SByteConstant ((sbyte) Value, Location); + } + if (target_type == TypeManager.short_type) { + if (in_checked_context){ + if (Value < short.MinValue || Value > short.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new ShortConstant ((short) Value, Location); + } + if (target_type == TypeManager.ushort_type) { + if (in_checked_context){ + if (Value < ushort.MinValue || Value > ushort.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new UShortConstant ((ushort) Value, Location); + } + if (target_type == TypeManager.int32_type) { + if (in_checked_context){ + if (Value < int.MinValue || Value > int.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new IntConstant ((int) Value, Location); + } + if (target_type == TypeManager.uint32_type) { + if (in_checked_context){ + if (Value < uint.MinValue || Value > uint.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new UIntConstant ((uint) Value, Location); + } + if (target_type == TypeManager.int64_type) { + if (in_checked_context){ + if (Value < long.MinValue || Value > long.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new LongConstant ((long) Value, Location); + } + if (target_type == TypeManager.uint64_type) { + if (in_checked_context){ + if (Value < ulong.MinValue || Value > ulong.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + return new ULongConstant ((ulong) Value, Location); + } + if (target_type == TypeManager.float_type) + return new FloatConstant ((float) Value, Location); + if (target_type == TypeManager.char_type) { + if (in_checked_context){ + if (Value < (double) char.MinValue || Value > (double) char.MaxValue || double.IsNaN (Value)) + throw new OverflowException (); + } + 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, Location loc): + base (loc) + { + Value = d; + } + + override public string AsString () + { + return Value.ToString () + "M"; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.decimal_type; + eclass = ExprClass.Value; + return this; + } + + public override object GetValue () + { + return (object) Value; + } + + public override void Emit (EmitContext ec) + { + int [] words = decimal.GetBits (Value); + int power = (words [3] >> 16) & 0xff; + + if (power == 0) { + if (Value <= int.MaxValue && Value >= int.MinValue) { + if (TypeManager.void_decimal_ctor_int_arg == null) { + TypeManager.void_decimal_ctor_int_arg = TypeManager.GetPredefinedConstructor ( + TypeManager.decimal_type, loc, TypeManager.int32_type); + + if (TypeManager.void_decimal_ctor_int_arg == null) + return; + } + + ec.EmitInt ((int) Value); + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg); + return; + } + + if (Value <= long.MaxValue && Value >= long.MinValue) { + if (TypeManager.void_decimal_ctor_long_arg == null) { + TypeManager.void_decimal_ctor_long_arg = TypeManager.GetPredefinedConstructor ( + TypeManager.decimal_type, loc, TypeManager.int64_type); + + if (TypeManager.void_decimal_ctor_long_arg == null) + return; + } + + ec.EmitLong ((long) Value); + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_long_arg); + return; + } + } + + ec.EmitInt (words [0]); + ec.EmitInt (words [1]); + ec.EmitInt (words [2]); + + // sign + ec.EmitInt (words [3] >> 31); + + // power + ec.EmitInt (power); + + if (TypeManager.void_decimal_ctor_five_args == null) { + TypeManager.void_decimal_ctor_five_args = TypeManager.GetPredefinedConstructor ( + TypeManager.decimal_type, loc, TypeManager.int32_type, TypeManager.int32_type, + TypeManager.int32_type, TypeManager.bool_type, TypeManager.byte_type); + + if (TypeManager.void_decimal_ctor_five_args == null) + return; + } + + ec.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args); + } + + public override bool IsDefaultValue { + get { + return Value == 0; + } + } + + public override bool IsNegative { + get { + return Value < 0; + } + } - } else if ((ModFlags & Modifiers.NEW) != 0) - WarningNotHiding (parent); + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec 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, Location loc): + base (loc) + { + Value = s; + } + + // FIXME: Escape the string. + override public string AsString () + { + return "\"" + Value + "\""; + } + + protected override Expression DoResolve (ResolveContext rc) + { + type = TypeManager.string_type; + eclass = ExprClass.Value; + return this; + } - FieldBuilder = parent.TypeBuilder.DefineField (Name, type, FieldAttr); + public override object GetValue () + { + return Value; } - /// - /// Emits the field value by evaluating the expression - /// - public void EmitConstant (TypeContainer parent) + public override void Emit (EmitContext ec) { - if (FieldBuilder == null) + if (Value == null) { + ec.Emit (OpCodes.Ldnull); return; - - EmitContext ec = new EmitContext (parent, Location, null, type, ModFlags); + } - Expr = Expression.Reduce (ec, Expr); + // + // Use string.Empty for both literals and constants even if + // it's not allowed at language level + // + if (Value.Length == 0 && RootContext.Optimize && !TypeManager.IsEqual (ec.CurrentType, TypeManager.string_type)) { + if (TypeManager.string_empty == null) + TypeManager.string_empty = TypeManager.GetPredefinedField (TypeManager.string_type, "Empty", loc, TypeManager.string_type); - if (!(Expr is Literal)) { - Report.Error (150, Location, "A constant value is expected"); - return; + if (TypeManager.string_empty != null) { + ec.Emit (OpCodes.Ldsfld, TypeManager.string_empty); + return; + } + } + + ec.Emit (OpCodes.Ldstr, Value); + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + // cast to object + if (type != targetType) + enc.Encode (type); + + enc.Encode (Value); + } + + public override bool IsDefaultValue { + get { + return Value == null; } + } - object val = ((Literal) Expr).GetValue (); + public override bool IsNegative { + get { + return false; + } + } - FieldBuilder.SetConstant (val); + public override bool IsNull { + get { + return IsDefaultValue; + } + } - TypeManager.RegisterField (FieldBuilder, val); - - return; + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + return null; } } -} + // + // Null constant can have its own type, think of `default (Foo)' + // + public class NullConstant : Constant + { + public NullConstant (TypeSpec type, Location loc) + : base (loc) + { + eclass = ExprClass.Value; + this.type = type; + } + + public override string AsString () + { + return GetSignatureForError (); + } + + public override Expression CreateExpressionTree (ResolveContext ec) + { + if (type == InternalType.Null || type == TypeManager.object_type) { + // Optimized version, also avoids referencing literal internal type + Arguments args = new Arguments (1); + args.Add (new Argument (this)); + return CreateExpressionFactoryCall (ec, "Constant", args); + } + + return base.CreateExpressionTree (ec); + } + + protected override Expression DoResolve (ResolveContext ec) + { + return this; + } + + public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType) + { + // Type it as string cast + if (targetType == TypeManager.object_type || targetType == TypeManager.null_type) + enc.Encode (TypeManager.string_type); + + var ac = targetType as ArrayContainer; + if (ac != null) { + if (ac.Rank != 1) + base.EncodeAttributeValue (rc, enc, targetType); + else + enc.Stream.Write (uint.MaxValue); + } else { + enc.Stream.Write (byte.MaxValue); + } + } + + public override void Emit (EmitContext ec) + { + ec.Emit (OpCodes.Ldnull); + + // Only to make verifier happy + if (TypeManager.IsGenericParameter (type)) + ec.Emit (OpCodes.Unbox_Any, type); + } + + public override string ExprClassName { + get { + return GetSignatureForError (); + } + } + + public override string GetSignatureForError () + { + return "null"; + } + + public override Constant ConvertExplicitly (bool inCheckedContext, TypeSpec targetType) + { + if (targetType.IsPointer) { + if (IsLiteral || this is NullPointer) + return new EmptyConstantCast (new NullPointer (loc), targetType); + + return null; + } + + // Exlude internal compiler types + if (targetType == InternalType.AnonymousMethod) + return null; + + if (!IsLiteral && !Convert.ImplicitStandardConversionExists (this, targetType)) + return null; + + if (TypeManager.IsReferenceType (targetType)) + return new NullConstant (targetType, loc); + + if (TypeManager.IsNullableType (targetType)) + return Nullable.LiftedNull.Create (targetType, loc); + + return null; + } + + public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec targetType) + { + return ConvertExplicitly (false, targetType); + } + + public override object GetValue () + { + return null; + } + + public override bool IsDefaultValue { + get { return true; } + } + + public override bool IsNegative { + get { return false; } + } + + public override bool IsNull { + get { return true; } + } + + public override bool IsZeroInteger { + get { return true; } + } + } + + /// + /// The value is constant, but when emitted has a side effect. This is + /// used by BitwiseAnd to ensure that the second expression is invoked + /// regardless of the value of the left side. + /// + public class SideEffectConstant : Constant { + public Constant value; + Expression side_effect; + + public SideEffectConstant (Constant value, Expression side_effect, Location loc) : base (loc) + { + this.value = value; + while (side_effect is SideEffectConstant) + side_effect = ((SideEffectConstant) side_effect).side_effect; + this.side_effect = side_effect; + } + + public override string AsString () + { + return value.AsString (); + } + + protected override Expression DoResolve (ResolveContext rc) + { + value = value.Resolve (rc); + + type = value.Type; + eclass = ExprClass.Value; + return this; + } + + public override object GetValue () + { + return value.GetValue (); + } + + public override void Emit (EmitContext ec) + { + side_effect.EmitSideEffect (ec); + value.Emit (ec); + } + + public override void EmitSideEffect (EmitContext ec) + { + side_effect.EmitSideEffect (ec); + value.EmitSideEffect (ec); + } + + public override bool IsDefaultValue { + get { return value.IsDefaultValue; } + } + public override bool IsNegative { + get { return value.IsNegative; } + } + + public override bool IsZeroInteger { + get { return value.IsZeroInteger; } + } + + public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type) + { + Constant new_value = value.ConvertExplicitly (in_checked_context, target_type); + return new_value == null ? null : new SideEffectConstant (new_value, side_effect, new_value.Location); + } + } +}