2 // constant.cs: Constants.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
11 namespace Mono.CSharp {
14 using System.Reflection.Emit;
17 /// Base class for constants and literals.
19 public abstract class Constant : Expression {
21 /// This is different from ToString in that ToString
22 /// is supposed to be there for debugging purposes,
23 /// and is not guaranteed to be useful for anything else,
24 /// AsString() will provide something that can be used
25 /// for round-tripping C# code. Maybe it can be used
26 /// for IL assembly as well.
28 public abstract string AsString ();
30 override public string ToString ()
32 return this.GetType ().Name + " (" + AsString () + ")";
36 /// This is used to obtain the actual value of the literal
37 /// cast into an object.
39 public abstract object GetValue ();
41 public virtual object GetTypedValue ()
47 /// Constants are always born in a fully resolved state
49 public override Expression DoResolve (EmitContext ec)
54 public override void Error_ValueCannotBeConverted (Location loc, Type t)
56 // string is not real constant
57 if (type == TypeManager.string_type)
58 base.Error_ValueCannotBeConverted (loc, t);
60 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
61 AsString (), TypeManager.CSharpName (t));
66 // The various ToXXXX conversion functions are used by the constant
67 // folding evaluator. A null value is returned if the conversion is
70 // Note: not all the patterns for catching `implicit_conv' are the same.
71 // some implicit conversions can never be performed between two types
72 // even if the conversion would be lossless (for example short to uint),
73 // but some conversions are explicitly permitted by the standard provided
74 // that there will be no loss of information (for example, int to uint).
76 public DoubleConstant ToDouble (Location loc)
78 DoubleConstant c = ConvertToDouble ();
81 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.double_type);
86 public FloatConstant ToFloat (Location loc)
88 FloatConstant c = ConvertToFloat ();
91 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.float_type);
96 public ULongConstant ToULong (Location loc)
98 ULongConstant c = ConvertToULong ();
101 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint64_type);
106 public LongConstant ToLong (Location loc)
108 LongConstant c = ConvertToLong ();
111 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int64_type);
116 public UIntConstant ToUInt (Location loc)
118 UIntConstant c = ConvertToUInt ();
121 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.uint32_type);
126 public IntConstant ToInt (Location loc)
128 IntConstant c = ConvertToInt ();
131 Convert.Error_CannotImplicitConversion (loc, Type, TypeManager.int32_type);
136 public DecimalConstant ToDecimal (Location loc)
138 DecimalConstant c = ConvertToDecimal ();
141 Convert.Error_CannotConvertType (loc, Type, TypeManager.decimal_type);
146 public virtual Constant ToType (Type type, Location loc)
151 if (type == TypeManager.object_type)
154 if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){
155 Error_ValueCannotBeConverted (loc, type);
159 // Special-case: The 0 literal can be converted to an enum value,
160 // and ImplicitStandardConversionExists will return true in that case.
161 if (IsZeroInteger && Type == TypeManager.int32_type && TypeManager.IsEnumType (type)) {
162 return new EnumConstant (this, type);
166 object constant_value = TypeManager.ChangeType (GetValue (), type, out fail);
168 Convert.Error_CannotImplicitConversion (loc, Type, type);
171 // We should always catch the error before this is ever
172 // reached, by calling Convert.ImplicitStandardConversionExists
174 throw new Exception (
175 String.Format ("LookupConstantValue: This should never be reached {0} {1}", Type, type));
179 if (type == TypeManager.int32_type)
180 retval = new IntConstant ((int) constant_value);
181 else if (type == TypeManager.uint32_type)
182 retval = new UIntConstant ((uint) constant_value);
183 else if (type == TypeManager.int64_type)
184 retval = new LongConstant ((long) constant_value);
185 else if (type == TypeManager.uint64_type)
186 retval = new ULongConstant ((ulong) constant_value);
187 else if (type == TypeManager.float_type)
188 retval = new FloatConstant ((float) constant_value);
189 else if (type == TypeManager.double_type)
190 retval = new DoubleConstant ((double) constant_value);
191 else if (type == TypeManager.string_type)
192 retval = new StringConstant ((string) constant_value);
193 else if (type == TypeManager.short_type)
194 retval = new ShortConstant ((short) constant_value);
195 else if (type == TypeManager.ushort_type)
196 retval = new UShortConstant ((ushort) constant_value);
197 else if (type == TypeManager.sbyte_type)
198 retval = new SByteConstant ((sbyte) constant_value);
199 else if (type == TypeManager.byte_type)
200 retval = new ByteConstant ((byte) constant_value);
201 else if (type == TypeManager.char_type)
202 retval = new CharConstant ((char) constant_value);
203 else if (type == TypeManager.bool_type)
204 retval = new BoolConstant ((bool) constant_value);
205 else if (type == TypeManager.decimal_type)
206 retval = new DecimalConstant ((decimal) constant_value);
208 throw new Exception ("LookupConstantValue: Unhandled constant type: " + type);
213 public virtual DecimalConstant ConvertToDecimal ()
218 public virtual DoubleConstant ConvertToDouble ()
223 public virtual FloatConstant ConvertToFloat ()
228 public virtual ULongConstant ConvertToULong ()
233 public virtual LongConstant ConvertToLong ()
238 public virtual UIntConstant ConvertToUInt ()
243 public virtual IntConstant ConvertToInt ()
248 public abstract Constant Increment ();
250 public abstract bool IsDefaultValue {
254 public abstract bool IsNegative {
259 // Returns true iff 1) the stack type of this is one of Object,
260 // int32, int64 and 2) this == 0 or this == null.
262 public virtual bool IsZeroInteger {
263 get { return false; }
267 public class BoolConstant : Constant {
268 public readonly bool Value;
270 public BoolConstant (bool val)
272 type = TypeManager.bool_type;
273 eclass = ExprClass.Value;
278 override public string AsString ()
280 return Value ? "true" : "false";
283 public override object GetValue ()
285 return (object) Value;
289 public override void Emit (EmitContext ec)
292 ec.ig.Emit (OpCodes.Ldc_I4_1);
294 ec.ig.Emit (OpCodes.Ldc_I4_0);
297 public override Constant Increment ()
299 throw new NotSupportedException ();
302 public override bool IsDefaultValue {
308 public override bool IsNegative {
314 public override bool IsZeroInteger {
315 get { return Value == false; }
319 public class ByteConstant : Constant {
320 public readonly byte Value;
322 public ByteConstant (byte v)
324 type = TypeManager.byte_type;
325 eclass = ExprClass.Value;
329 public override void Emit (EmitContext ec)
331 IntLiteral.EmitInt (ec.ig, Value);
334 public override string AsString ()
336 return Value.ToString ();
339 public override object GetValue ()
344 public override DoubleConstant ConvertToDouble ()
346 return new DoubleConstant (Value);
349 public override FloatConstant ConvertToFloat ()
351 return new FloatConstant (Value);
354 public override ULongConstant ConvertToULong ()
356 return new ULongConstant (Value);
359 public override LongConstant ConvertToLong ()
361 return new LongConstant (Value);
364 public override UIntConstant ConvertToUInt ()
366 return new UIntConstant (Value);
369 public override IntConstant ConvertToInt ()
371 return new IntConstant (Value);
374 public override Constant Increment ()
376 return new ByteConstant (checked ((byte)(Value + 1)));
379 public override bool IsDefaultValue {
385 public override bool IsNegative {
391 public override bool IsZeroInteger {
392 get { return Value == 0; }
396 public class CharConstant : Constant {
397 public readonly char Value;
399 public CharConstant (char v)
401 type = TypeManager.char_type;
402 eclass = ExprClass.Value;
406 public override void Emit (EmitContext ec)
408 IntLiteral.EmitInt (ec.ig, Value);
411 static public string descape (char c)
437 return c.ToString ();
440 public override string AsString ()
442 return "\"" + descape (Value) + "\"";
445 public override object GetValue ()
450 public override DoubleConstant ConvertToDouble ()
452 return new DoubleConstant (Value);
455 public override FloatConstant ConvertToFloat ()
457 return new FloatConstant (Value);
460 public override ULongConstant ConvertToULong ()
462 return new ULongConstant (Value);
465 public override LongConstant ConvertToLong ()
467 return new LongConstant (Value);
470 public override UIntConstant ConvertToUInt ()
472 return new UIntConstant (Value);
475 public override IntConstant ConvertToInt ()
477 return new IntConstant (Value);
480 public override Constant Increment ()
482 return new CharConstant (checked ((char)(Value + 1)));
485 public override bool IsDefaultValue {
491 public override bool IsNegative {
497 public override bool IsZeroInteger {
498 get { return Value == '\0'; }
502 public class SByteConstant : Constant {
503 public readonly sbyte Value;
505 public SByteConstant (sbyte v)
507 type = TypeManager.sbyte_type;
508 eclass = ExprClass.Value;
512 public override void Emit (EmitContext ec)
514 IntLiteral.EmitInt (ec.ig, Value);
517 public override string AsString ()
519 return Value.ToString ();
522 public override object GetValue ()
527 public override DoubleConstant ConvertToDouble ()
529 return new DoubleConstant (Value);
532 public override FloatConstant ConvertToFloat ()
534 return new FloatConstant (Value);
537 public override ULongConstant ConvertToULong ()
540 return new ULongConstant ((ulong) Value);
545 public override LongConstant ConvertToLong ()
547 return new LongConstant (Value);
550 public override UIntConstant ConvertToUInt ()
555 public override IntConstant ConvertToInt ()
557 return new IntConstant (Value);
560 public override Constant Increment ()
562 return new SByteConstant (checked((sbyte)(Value + 1)));
565 public override bool IsDefaultValue {
571 public override bool IsNegative {
577 public override bool IsZeroInteger {
578 get { return Value == 0; }
582 public class ShortConstant : Constant {
583 public readonly short Value;
585 public ShortConstant (short v)
587 type = TypeManager.short_type;
588 eclass = ExprClass.Value;
592 public override void Emit (EmitContext ec)
594 IntLiteral.EmitInt (ec.ig, Value);
597 public override string AsString ()
599 return Value.ToString ();
602 public override object GetValue ()
607 public override DoubleConstant ConvertToDouble ()
609 return new DoubleConstant (Value);
612 public override FloatConstant ConvertToFloat ()
614 return new FloatConstant (Value);
617 public override ULongConstant ConvertToULong ()
622 public override LongConstant ConvertToLong ()
624 return new LongConstant (Value);
627 public override UIntConstant ConvertToUInt ()
632 public override IntConstant ConvertToInt ()
634 return new IntConstant (Value);
637 public override Constant Increment ()
639 return new ShortConstant (checked((short)(Value + 1)));
642 public override bool IsDefaultValue {
648 public override bool IsZeroInteger {
649 get { return Value == 0; }
652 public override bool IsNegative {
659 public class UShortConstant : Constant {
660 public readonly ushort Value;
662 public UShortConstant (ushort v)
664 type = TypeManager.ushort_type;
665 eclass = ExprClass.Value;
669 public override void Emit (EmitContext ec)
671 IntLiteral.EmitInt (ec.ig, Value);
674 public override string AsString ()
676 return Value.ToString ();
679 public override object GetValue ()
684 public override DoubleConstant ConvertToDouble ()
686 return new DoubleConstant (Value);
689 public override FloatConstant ConvertToFloat ()
691 return new FloatConstant (Value);
694 public override ULongConstant ConvertToULong ()
696 return new ULongConstant (Value);
699 public override LongConstant ConvertToLong ()
701 return new LongConstant (Value);
704 public override UIntConstant ConvertToUInt ()
706 return new UIntConstant (Value);
709 public override IntConstant ConvertToInt ()
711 return new IntConstant (Value);
714 public override Constant Increment ()
716 return new UShortConstant (checked((ushort)(Value + 1)));
719 public override bool IsDefaultValue {
725 public override bool IsNegative {
731 public override bool IsZeroInteger {
732 get { return Value == 0; }
736 public class IntConstant : Constant {
737 public readonly int Value;
739 public IntConstant (int v)
741 type = TypeManager.int32_type;
742 eclass = ExprClass.Value;
746 static public void EmitInt (ILGenerator ig, int i)
750 ig.Emit (OpCodes.Ldc_I4_M1);
754 ig.Emit (OpCodes.Ldc_I4_0);
758 ig.Emit (OpCodes.Ldc_I4_1);
762 ig.Emit (OpCodes.Ldc_I4_2);
766 ig.Emit (OpCodes.Ldc_I4_3);
770 ig.Emit (OpCodes.Ldc_I4_4);
774 ig.Emit (OpCodes.Ldc_I4_5);
778 ig.Emit (OpCodes.Ldc_I4_6);
782 ig.Emit (OpCodes.Ldc_I4_7);
786 ig.Emit (OpCodes.Ldc_I4_8);
790 if (i >= -128 && i <= 127){
791 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
793 ig.Emit (OpCodes.Ldc_I4, i);
798 public override void Emit (EmitContext ec)
800 EmitInt (ec.ig, Value);
803 public override string AsString ()
805 return Value.ToString ();
808 public override object GetValue ()
813 public override DecimalConstant ConvertToDecimal()
815 return new DecimalConstant (Value);
818 public override DoubleConstant ConvertToDouble ()
820 return new DoubleConstant (Value);
823 public override FloatConstant ConvertToFloat ()
825 return new FloatConstant (Value);
828 public override ULongConstant ConvertToULong ()
833 return new ULongConstant ((ulong) Value);
836 public override LongConstant ConvertToLong ()
838 return new LongConstant (Value);
841 public override UIntConstant ConvertToUInt ()
846 return new UIntConstant ((uint) Value);
849 public override IntConstant ConvertToInt ()
854 public override Constant Increment ()
856 return new IntConstant (checked(Value + 1));
859 public override bool IsDefaultValue {
865 public override bool IsNegative {
871 public override bool IsZeroInteger {
872 get { return Value == 0; }
876 public class UIntConstant : Constant {
877 public readonly uint Value;
879 public UIntConstant (uint v)
881 type = TypeManager.uint32_type;
882 eclass = ExprClass.Value;
886 public override void Emit (EmitContext ec)
888 IntLiteral.EmitInt (ec.ig, unchecked ((int) Value));
891 public override string AsString ()
893 return Value.ToString ();
896 public override object GetValue ()
901 public override DoubleConstant ConvertToDouble ()
903 return new DoubleConstant (Value);
906 public override FloatConstant ConvertToFloat ()
908 return new FloatConstant (Value);
911 public override ULongConstant ConvertToULong ()
913 return new ULongConstant (Value);
916 public override LongConstant ConvertToLong ()
918 return new LongConstant (Value);
921 public override UIntConstant ConvertToUInt ()
926 public override IntConstant ConvertToInt ()
931 public override Constant Increment ()
933 return new UIntConstant (checked(Value + 1));
936 public override bool IsDefaultValue {
942 public override bool IsNegative {
948 public override bool IsZeroInteger {
949 get { return Value == 0; }
953 public class LongConstant : Constant {
954 public readonly long Value;
956 public LongConstant (long v)
958 type = TypeManager.int64_type;
959 eclass = ExprClass.Value;
963 public override void Emit (EmitContext ec)
965 ILGenerator ig = ec.ig;
967 EmitLong (ig, Value);
970 static public void EmitLong (ILGenerator ig, long l)
973 IntLiteral.EmitInt (ig, unchecked ((int) l));
974 ig.Emit (OpCodes.Conv_U8);
976 ig.Emit (OpCodes.Ldc_I8, l);
980 public override string AsString ()
982 return Value.ToString ();
985 public override object GetValue ()
990 public override DoubleConstant ConvertToDouble ()
992 return new DoubleConstant (Value);
995 public override FloatConstant ConvertToFloat ()
997 return new FloatConstant (Value);
1000 public override ULongConstant ConvertToULong ()
1005 return new ULongConstant ((ulong) Value);
1008 public override LongConstant ConvertToLong ()
1013 public override UIntConstant ConvertToUInt ()
1018 public override IntConstant ConvertToInt ()
1023 public override Constant Increment ()
1025 return new LongConstant (checked(Value + 1));
1028 public override bool IsDefaultValue {
1034 public override bool IsNegative {
1040 public override bool IsZeroInteger {
1041 get { return Value == 0; }
1045 public class ULongConstant : Constant {
1046 public readonly ulong Value;
1048 public ULongConstant (ulong v)
1050 type = TypeManager.uint64_type;
1051 eclass = ExprClass.Value;
1055 public override void Emit (EmitContext ec)
1057 ILGenerator ig = ec.ig;
1059 LongLiteral.EmitLong (ig, unchecked ((long) Value));
1062 public override string AsString ()
1064 return Value.ToString ();
1067 public override object GetValue ()
1072 public override DoubleConstant ConvertToDouble ()
1074 return new DoubleConstant (Value);
1077 public override FloatConstant ConvertToFloat ()
1079 return new FloatConstant (Value);
1082 public override ULongConstant ConvertToULong ()
1087 public override LongConstant ConvertToLong ()
1092 public override UIntConstant ConvertToUInt ()
1097 public override IntConstant ConvertToInt ()
1102 public override Constant Increment ()
1104 return new ULongConstant (checked(Value + 1));
1107 public override bool IsDefaultValue {
1113 public override bool IsNegative {
1119 public override bool IsZeroInteger {
1120 get { return Value == 0; }
1124 public class FloatConstant : Constant {
1125 public readonly float Value;
1127 public FloatConstant (float v)
1129 type = TypeManager.float_type;
1130 eclass = ExprClass.Value;
1134 public override void Emit (EmitContext ec)
1136 ec.ig.Emit (OpCodes.Ldc_R4, Value);
1139 public override string AsString ()
1141 return Value.ToString ();
1144 public override object GetValue ()
1149 public override DoubleConstant ConvertToDouble ()
1151 return new DoubleConstant (Value);
1154 public override FloatConstant ConvertToFloat ()
1159 public override LongConstant ConvertToLong ()
1164 public override UIntConstant ConvertToUInt ()
1169 public override IntConstant ConvertToInt ()
1174 public override Constant Increment ()
1176 return new FloatConstant (checked(Value + 1));
1179 public override bool IsDefaultValue {
1185 public override bool IsNegative {
1192 public class DoubleConstant : Constant {
1193 public readonly double Value;
1195 public DoubleConstant (double v)
1197 type = TypeManager.double_type;
1198 eclass = ExprClass.Value;
1202 public override void Emit (EmitContext ec)
1204 ec.ig.Emit (OpCodes.Ldc_R8, Value);
1207 public override string AsString ()
1209 return Value.ToString ();
1212 public override object GetValue ()
1217 public override DoubleConstant ConvertToDouble ()
1222 public override FloatConstant ConvertToFloat ()
1227 public override ULongConstant ConvertToULong ()
1232 public override LongConstant ConvertToLong ()
1237 public override UIntConstant ConvertToUInt ()
1242 public override IntConstant ConvertToInt ()
1247 public override Constant Increment ()
1249 return new DoubleConstant (checked(Value + 1));
1252 public override bool IsDefaultValue {
1258 public override bool IsNegative {
1265 public class DecimalConstant : Constant {
1266 public readonly decimal Value;
1268 public DecimalConstant (decimal d)
1270 type = TypeManager.decimal_type;
1271 eclass = ExprClass.Value;
1275 override public string AsString ()
1277 return Value.ToString ();
1280 public override object GetValue ()
1282 return (object) Value;
1285 public override void Emit (EmitContext ec)
1287 ILGenerator ig = ec.ig;
1289 int [] words = Decimal.GetBits (Value);
1290 int power = (words [3] >> 16) & 0xff;
1292 if (power == 0 && Value <= int.MaxValue && Value >= int.MinValue)
1294 IntConstant.EmitInt (ig, (int)Value);
1295 ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_int_arg);
1301 // FIXME: we could optimize this, and call a better
1305 IntConstant.EmitInt (ig, words [0]);
1306 IntConstant.EmitInt (ig, words [1]);
1307 IntConstant.EmitInt (ig, words [2]);
1310 IntConstant.EmitInt (ig, words [3] >> 31);
1313 IntConstant.EmitInt (ig, power);
1315 ig.Emit (OpCodes.Newobj, TypeManager.void_decimal_ctor_five_args);
1318 public override Constant Increment ()
1320 return new DecimalConstant (checked (Value + 1));
1323 public override bool IsDefaultValue {
1329 public override bool IsNegative {
1336 public class StringConstant : Constant {
1337 public readonly string Value;
1339 public StringConstant (string s)
1341 type = TypeManager.string_type;
1342 eclass = ExprClass.Value;
1346 // FIXME: Escape the string.
1347 override public string AsString ()
1349 return "\"" + Value + "\"";
1352 public override object GetValue ()
1357 public override void Emit (EmitContext ec)
1360 ec.ig.Emit (OpCodes.Ldnull);
1362 ec.ig.Emit (OpCodes.Ldstr, Value);
1365 public override Constant Increment ()
1367 throw new NotSupportedException ();
1370 public override bool IsDefaultValue {
1372 return Value == null;
1376 public override bool IsNegative {