Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Ast / ConstantExpression.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 #if FEATURE_CORE_DLR
17 using System.Linq.Expressions;
18 #else
19 using Microsoft.Scripting.Ast;
20 #endif
21
22 #if FEATURE_NUMERICS
23 using BigInt = System.Numerics.BigInteger;
24 using Complex = System.Numerics.Complex;
25 #endif
26
27 using System;
28 using System.Reflection;
29 using Microsoft.Scripting.Generation;
30 using Microsoft.Scripting.Math;
31 using Microsoft.Scripting.Utils;
32
33 namespace Microsoft.Scripting.Ast {
34     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")]
35     public static partial class Utils {
36         private static readonly ConstantExpression TrueLiteral = Expression.Constant(true, typeof(bool));
37         private static readonly ConstantExpression FalseLiteral = Expression.Constant(false, typeof(bool));
38         private static readonly ConstantExpression NullLiteral = Expression.Constant(null, typeof(object));
39         private static readonly ConstantExpression EmptyStringLiteral = Expression.Constant(String.Empty, typeof(string));
40         private static readonly ConstantExpression[] IntCache = new ConstantExpression[100];
41
42         /// <summary>
43         /// Wraps the given value in a WeakReference and returns a tree that will retrieve
44         /// the value from the WeakReference.
45         /// </summary>
46         public static MemberExpression WeakConstant(object value) {
47             System.Diagnostics.Debug.Assert(!(value is Expression));
48             return Expression.Property(
49                 Constant(new WeakReference(value)),
50                 typeof(WeakReference).GetDeclaredProperty("Target")
51             );
52         }
53
54         public static ConstantExpression Constant(object value, Type type) {
55             return Expression.Constant(value, type);
56         }
57
58         // The helper API should return ConstantExpression after SymbolConstantExpression goes away
59         public static Expression Constant(object value) {
60             if (value == null) {
61                 return NullLiteral;
62             }
63
64             BigInteger bi = value as BigInteger;
65             if ((object)bi != null) {
66                 return BigIntegerConstant(bi);
67 #if FEATURE_NUMERICS
68             } else if (value is BigInt) {
69                 return BigIntConstant((BigInt)value);
70             } else if (value is Complex) {
71                 return ComplexConstant((Complex)value);
72 #endif
73             } else if (value is Complex64) {
74                 return Complex64Constant((Complex64)value);
75             } else if (value is Type) {
76                 return Expression.Constant(value, typeof(Type));
77             } else if (value is ConstructorInfo) {
78                 return Expression.Constant(value, typeof(ConstructorInfo));
79             } else if (value is EventInfo) {
80                 return Expression.Constant(value, typeof(EventInfo));
81             } else if (value is FieldInfo) {
82                 return Expression.Constant(value, typeof(FieldInfo));
83             } else if (value is MethodInfo) {
84                 return Expression.Constant(value, typeof(MethodInfo));
85             } else if (value is PropertyInfo) {
86                 return Expression.Constant(value, typeof(PropertyInfo));
87             } else {
88                 Type t = value.GetType();
89                 if (!t.GetTypeInfo().IsEnum) {
90                     switch (t.GetTypeCode()) {
91                         case TypeCode.Boolean:
92                             return (bool)value ? TrueLiteral : FalseLiteral;
93                         case TypeCode.Int32:
94                             int x = (int)value;
95                             int cacheIndex = x + 2;
96                             if (cacheIndex >= 0 && cacheIndex < IntCache.Length) {
97                                 ConstantExpression res;
98                                 if ((res = IntCache[cacheIndex]) == null) {
99                                     IntCache[cacheIndex] = res = Constant(x, typeof(int));
100                                 }
101                                 return res;
102                             }
103                             break;
104                         case TypeCode.String:
105                             if (String.IsNullOrEmpty((string)value)) {
106                                 return EmptyStringLiteral;
107                             }
108                             break;
109                     }
110                 }
111                 return Expression.Constant(value);
112             }
113         }
114
115         private static Expression BigIntegerConstant(BigInteger value) {
116             int ival;
117             if (value.AsInt32(out ival)) {
118                 return Expression.Call(
119                     new Func<int, BigInteger>(BigInteger.Create).GetMethodInfo(),
120                     Constant(ival)
121                 );
122             }
123
124             long lval;
125             if (value.AsInt64(out lval)) {
126                 return Expression.Call(
127                     new Func<long, BigInteger>(BigInteger.Create).GetMethodInfo(),
128                     Constant(lval)
129                 );
130             }
131
132 #if !FEATURE_NUMERICS
133             return Expression.Call(
134                 new Func<int, uint[], BigInteger>(CompilerHelpers.CreateBigInteger).Method,
135                 Constant((int)value.Sign),
136                 CreateArray<uint>(value.GetWords())
137             );
138 #else
139             return Expression.Call(
140                 new Func<bool, byte[], BigInteger>(CompilerHelpers.CreateBigInteger).GetMethodInfo(),
141                 Constant(value.Sign < 0),
142                 CreateArray<byte>(value.Abs().ToByteArray())
143             );
144         }
145
146         private static Expression BigIntConstant(BigInt value) {
147             int ival;
148             if (value.AsInt32(out ival)) {
149                 return Expression.Call(
150                     new Func<int, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
151                     Constant(ival)
152                 );
153             }
154
155             long lval;
156             if (value.AsInt64(out lval)) {
157                 return Expression.Call(
158                     new Func<long, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
159                     Constant(lval)
160                 );
161             }
162
163             return Expression.Call(
164                 new Func<bool, byte[], BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(),
165                 Constant(value.Sign < 0),
166                 CreateArray<byte>(value.Abs().ToByteArray())
167             );
168 #endif
169         }
170
171         private static Expression CreateArray<T>(T[] array) {
172             // TODO: could we use blobs?
173             Expression[] init = new Expression[array.Length];
174             for (int i = 0; i < init.Length; i++) {
175                 init[i] = Constant(array[i]);
176             }
177             return Expression.NewArrayInit(typeof(T), init);
178         }
179
180 #if FEATURE_NUMERICS
181         private static Expression ComplexConstant(Complex value) {
182             if (value.Real != 0.0) {
183                 if (value.Imaginary() != 0.0) {
184                     return Expression.Call(
185                         new Func<double, double, Complex>(MathUtils.MakeComplex).GetMethodInfo(),
186                         Constant(value.Real),
187                         Constant(value.Imaginary())
188                     );
189                 } else {
190                     return Expression.Call(
191                         new Func<double, Complex>(MathUtils.MakeReal).GetMethodInfo(),
192                         Constant(value.Real)
193                     );
194                 }
195             } else {
196                 return Expression.Call(
197                     new Func<double, Complex>(MathUtils.MakeImaginary).GetMethodInfo(),
198                     Constant(value.Imaginary())
199                 );
200             }
201         }
202 #endif
203
204         private static Expression Complex64Constant(Complex64 value) {
205             if (value.Real != 0.0) {
206                 if (value.Imag != 0.0) {
207                     return Expression.Call(
208                         new Func<double, double, Complex64>(Complex64.Make).GetMethodInfo(),
209                         Constant(value.Real),
210                         Constant(value.Imag)
211                     );
212                 } else {
213                     return Expression.Call(
214                         new Func<double, Complex64>(Complex64.MakeReal).GetMethodInfo(),
215                         Constant(value.Real)
216                     );
217                 }
218             } else {
219                 return Expression.Call(
220                     new Func<double, Complex64>(Complex64.MakeImaginary).GetMethodInfo(),
221                     Constant(value.Imag)
222                 );
223             }
224         }
225     }
226 }