2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Core / System.Linq.Expressions / ConstantExpression.cs
blob1a8c4d7b7aa42c5e8be78a319105001730950387
1 //
2 // ConstantExpression.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@novell.com)
6 // Miguel de Icaza (miguel@novell.com)
7 //
8 // Some code is based on the Mono C# compiler:
9 // Marek Safar (marek.safar@seznam.cz)
10 // Martin Baulig (martin@ximian.com)
12 // (C) 2001-2008 Novell, Inc. (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System;
35 using System.Reflection;
36 using System.Reflection.Emit;
38 namespace System.Linq.Expressions {
40 public sealed class ConstantExpression : Expression {
41 object value;
43 public object Value {
44 get { return value; }
47 internal ConstantExpression (object value, Type type)
48 : base (ExpressionType.Constant, type)
50 this.value = value;
53 internal override void Emit (EmitContext ec)
55 if (Type.IsNullable ()) {
56 EmitNullableConstant (ec, Type, value);
57 return;
60 EmitConstant (ec, Type, value);
63 void EmitNullableConstant (EmitContext ec, Type type, object value)
65 if (value == null) {
66 var ig = ec.ig;
67 var local = ig.DeclareLocal (type);
68 ig.Emit (OpCodes.Ldloca, local);
69 ig.Emit (OpCodes.Initobj, type);
70 ig.Emit (OpCodes.Ldloc, local);
71 } else {
72 EmitConstant (ec, type.GetFirstGenericArgument (), value);
73 ec.EmitNullableNew (type);
77 void EmitConstant (EmitContext ec, Type type, object value)
79 var ig = ec.ig;
81 switch (Type.GetTypeCode (type)){
82 case TypeCode.Byte:
83 ig.Emit (OpCodes.Ldc_I4, (int) ((byte)value));
84 return;
86 case TypeCode.SByte:
87 ig.Emit (OpCodes.Ldc_I4, (int) ((sbyte)value));
88 return;
90 case TypeCode.Int16:
91 ig.Emit (OpCodes.Ldc_I4, (int) ((short)value));
92 return;
94 case TypeCode.UInt16:
95 ig.Emit (OpCodes.Ldc_I4, (int) ((ushort)value));
96 return;
98 case TypeCode.Int32:
99 ig.Emit (OpCodes.Ldc_I4, (int) value);
100 return;
102 case TypeCode.UInt32:
103 ig.Emit (OpCodes.Ldc_I4, unchecked ((int) ((uint)Value)));
104 return;
106 case TypeCode.Int64:
107 ig.Emit (OpCodes.Ldc_I8, (long) value);
108 return;
110 case TypeCode.UInt64:
111 ig.Emit (OpCodes.Ldc_I8, unchecked ((long) ((ulong)value)));
112 return;
114 case TypeCode.Boolean:
115 if ((bool) Value)
116 ig.Emit (OpCodes.Ldc_I4_1);
117 else
118 ec.ig.Emit (OpCodes.Ldc_I4_0);
119 return;
121 case TypeCode.Char:
122 ig.Emit (OpCodes.Ldc_I4, (int) ((char) value));
123 return;
125 case TypeCode.Single:
126 ig.Emit (OpCodes.Ldc_R4, (float) value);
127 return;
129 case TypeCode.Double:
130 ig.Emit (OpCodes.Ldc_R8, (double) value);
131 return;
133 case TypeCode.Decimal: {
134 Decimal v = (decimal) value;
135 int [] words = Decimal.GetBits (v);
136 int power = (words [3] >> 16) & 0xff;
137 Type ti = typeof (int);
139 if (power == 0 && v <= int.MaxValue && v >= int.MinValue) {
140 ig.Emit (OpCodes.Ldc_I4, (int) v);
142 ig.Emit (OpCodes.Newobj, typeof (Decimal).GetConstructor (new Type [1] { ti }));
143 return;
145 ig.Emit (OpCodes.Ldc_I4, words [0]);
146 ig.Emit (OpCodes.Ldc_I4, words [1]);
147 ig.Emit (OpCodes.Ldc_I4, words [2]);
148 // sign
149 ig.Emit (OpCodes.Ldc_I4, words [3] >> 31);
151 // power
152 ig.Emit (OpCodes.Ldc_I4, power);
154 ig.Emit (OpCodes.Newobj, typeof (Decimal).GetConstructor (new Type [5] { ti, ti, ti, typeof(bool), typeof(byte) }));
155 return;
158 case TypeCode.DateTime: {
159 var date = (DateTime) value;
160 var local = ig.DeclareLocal (typeof (DateTime));
162 ig.Emit (OpCodes.Ldloca, local);
163 ig.Emit (OpCodes.Ldc_I8, date.Ticks);
164 ig.Emit (OpCodes.Ldc_I4, (int) date.Kind);
165 ig.Emit (OpCodes.Call, typeof (DateTime).GetConstructor (new [] { typeof (long), typeof (DateTimeKind) }));
166 ig.Emit (OpCodes.Ldloc, local);
168 return;
171 case TypeCode.DBNull:
172 ig.Emit (OpCodes.Ldsfld, typeof (DBNull).GetField ("Value", BindingFlags.Public | BindingFlags.Static));
173 return;
175 case TypeCode.String:
176 EmitIfNotNull (ec, c => c.ig.Emit (OpCodes.Ldstr, (string) value));
177 return;
179 case TypeCode.Object:
180 EmitIfNotNull (ec, c => c.EmitReadGlobal (value));
181 return;
184 throw new NotImplementedException (String.Format ("No support for constants of type {0} yet", Type));
187 void EmitIfNotNull (EmitContext ec, Action<EmitContext> emit)
189 if (value == null) {
190 ec.ig.Emit (OpCodes.Ldnull);
191 return;
194 emit (ec);