1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Linq.Expressions;
19 using Microsoft.Scripting.Ast;
23 using System.Reflection;
25 using Microsoft.Scripting.Utils;
26 using AstUtils = Microsoft.Scripting.Ast.Utils;
28 namespace Microsoft.Scripting.Ast {
29 public static partial class Utils {
32 /// Null coalescing expression
33 /// {result} ::= ((tmp = {_left}) == null) ? {right} : tmp
34 /// '??' operator in C#.
36 public static Expression Coalesce(Expression left, Expression right, out ParameterExpression temp) {
37 return CoalesceInternal(left, right, null, false, out temp);
41 /// True coalescing expression.
42 /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp
43 /// Generalized AND semantics.
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);
51 /// False coalescing expression.
52 /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right}
53 /// Generalized OR semantics.
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);
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");
64 // A bit too strict, but on a safe side.
65 ContractUtils.Requires(left.Type == right.Type, "Expression types must match");
67 temp = Expression.Variable(left.Type, "tmp_left");
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.");
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));
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));
93 return Expression.Condition(condition, t, f);
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);
104 /// True coalescing expression.
105 /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp
106 /// Generalized AND semantics.
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);
117 /// False coalescing expression.
118 /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right}
119 /// Generalized OR semantics.
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);
129 public static BinaryExpression Update(this BinaryExpression expression, Expression left, Expression right) {
130 return expression.Update(left, expression.Conversion, right);