Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Ast / BinaryExpression.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 using System;
23 using System.Reflection;
24 using System.Dynamic;
25 using Microsoft.Scripting.Utils;
26 using AstUtils = Microsoft.Scripting.Ast.Utils;
27
28 namespace Microsoft.Scripting.Ast {
29     public static partial class Utils {
30 #if !MONO_INTERPRETER
31         /// <summary>
32         /// Null coalescing expression
33         /// {result} ::= ((tmp = {_left}) == null) ? {right} : tmp
34         /// '??' operator in C#.
35         /// </summary>
36         public static Expression Coalesce(Expression left, Expression right, out ParameterExpression temp) {
37             return CoalesceInternal(left, right, null, false, out temp);
38         }
39
40         /// <summary>
41         /// True coalescing expression.
42         /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp
43         /// Generalized AND semantics.
44         /// </summary>
45         public static Expression CoalesceTrue(Expression left, Expression right, MethodInfo isTrue, out ParameterExpression temp) {
46             ContractUtils.RequiresNotNull(isTrue, "isTrue");
47             return CoalesceInternal(left, right, isTrue, false, out temp);
48         }
49
50         /// <summary>
51         /// False coalescing expression.
52         /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right}
53         /// Generalized OR semantics.
54         /// </summary>
55         public static Expression CoalesceFalse(Expression left, Expression right, MethodInfo isTrue, out ParameterExpression temp) {
56             ContractUtils.RequiresNotNull(isTrue, "isTrue");
57             return CoalesceInternal(left, right, isTrue, true, out temp);
58         }
59
60         private static Expression CoalesceInternal(Expression left, Expression right, MethodInfo isTrue, bool isReverse, out ParameterExpression temp) {
61             ContractUtils.RequiresNotNull(left, "left");
62             ContractUtils.RequiresNotNull(right, "right");
63
64             // A bit too strict, but on a safe side.
65             ContractUtils.Requires(left.Type == right.Type, "Expression types must match");
66
67             temp = Expression.Variable(left.Type, "tmp_left");
68
69             Expression condition;
70             if (isTrue != null) {
71                 ContractUtils.Requires(isTrue.ReturnType == typeof(bool), "isTrue", "Predicate must return bool.");
72                 ParameterInfo[] parameters = isTrue.GetParameters();
73                 ContractUtils.Requires(parameters.Length == 1, "isTrue", "Predicate must take one parameter.");
74                 ContractUtils.Requires(isTrue.IsStatic && isTrue.IsPublic, "isTrue", "Predicate must be public and static.");
75
76                 Type pt = parameters[0].ParameterType;
77                 ContractUtils.Requires(TypeUtils.CanAssign(pt, left.Type), "left", "Incorrect left expression type");
78                 condition = Expression.Call(isTrue, Expression.Assign(temp, left));
79             } else {
80                 ContractUtils.Requires(TypeUtils.CanCompareToNull(left.Type), "left", "Incorrect left expression type");
81                 condition = Expression.Equal(Expression.Assign(temp, left), AstUtils.Constant(null, left.Type));
82             }
83
84             Expression t, f;
85             if (isReverse) {
86                 t = temp;
87                 f = right;
88             } else {
89                 t = right;
90                 f = temp;
91             }
92
93             return Expression.Condition(condition, t, f);
94         }
95
96         public static Expression Coalesce(LambdaBuilder builder, Expression left, Expression right) {
97             ParameterExpression temp;
98             Expression result = Coalesce(left, right, out temp);
99             builder.AddHiddenVariable(temp);
100             return result;
101         }
102
103         /// <summary>
104         /// True coalescing expression.
105         /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp
106         /// Generalized AND semantics.
107         /// </summary>
108         public static Expression CoalesceTrue(LambdaBuilder builder, Expression left, Expression right, MethodInfo isTrue) {
109             ContractUtils.RequiresNotNull(isTrue, "isTrue");
110             ParameterExpression temp;
111             Expression result = CoalesceTrue(left, right, isTrue, out temp);
112             builder.AddHiddenVariable(temp);
113             return result;
114         }
115
116         /// <summary>
117         /// False coalescing expression.
118         /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right}
119         /// Generalized OR semantics.
120         /// </summary>
121         public static Expression CoalesceFalse(LambdaBuilder builder, Expression left, Expression right, MethodInfo isTrue) {
122             ContractUtils.RequiresNotNull(isTrue, "isTrue");
123             ParameterExpression temp;
124             Expression result = CoalesceFalse(left, right, isTrue, out temp);
125             builder.AddHiddenVariable(temp);
126             return result;
127         }
128 #endif
129         public static BinaryExpression Update(this BinaryExpression expression, Expression left, Expression right) {
130             return expression.Update(left, expression.Conversion, right);
131         }
132     }
133 }