BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / ParameterExpression.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 using System;
17 using System.Diagnostics;
18 using System.Dynamic.Utils;
19
20 #if SILVERLIGHT
21 using System.Core;
22 #endif
23
24 #if CLR2
25 namespace Microsoft.Scripting.Ast {
26 #else
27 namespace System.Linq.Expressions {
28 #endif
29
30     /// <summary>
31     /// Represents a named parameter expression.
32     /// </summary>
33 #if !SILVERLIGHT
34     [DebuggerTypeProxy(typeof(Expression.ParameterExpressionProxy))]
35 #endif
36     public class ParameterExpression : Expression {
37         private readonly string _name;
38
39         internal ParameterExpression(string name) {
40             _name = name;
41         }
42
43         internal static ParameterExpression Make(Type type, string name, bool isByRef) {
44             if (isByRef) {
45                 return new ByRefParameterExpression(type, name);
46             } else {
47                 if (!type.IsEnum) {
48                     switch (Type.GetTypeCode(type)) {
49                         case TypeCode.Boolean: return new PrimitiveParameterExpression<Boolean>(name);
50                         case TypeCode.Byte: return new PrimitiveParameterExpression<Byte>(name);
51                         case TypeCode.Char: return new PrimitiveParameterExpression<Char>(name);
52                         case TypeCode.DateTime: return new PrimitiveParameterExpression<DateTime>(name);
53                         case TypeCode.DBNull: return new PrimitiveParameterExpression<DBNull>(name);
54                         case TypeCode.Decimal: return new PrimitiveParameterExpression<Decimal>(name);
55                         case TypeCode.Double: return new PrimitiveParameterExpression<Double>(name);
56                         case TypeCode.Int16: return new PrimitiveParameterExpression<Int16>(name);
57                         case TypeCode.Int32: return new PrimitiveParameterExpression<Int32>(name);
58                         case TypeCode.Int64: return new PrimitiveParameterExpression<Int64>(name);
59                         case TypeCode.Object:
60                             // common reference types which we optimize go here.  Of course object is in
61                             // the list, the others are driven by profiling of various workloads.  This list
62                             // should be kept short.
63                             if (type == typeof(object)) {
64                                 return new ParameterExpression(name);
65                             } else if (type == typeof(Exception)) {
66                                 return new PrimitiveParameterExpression<Exception>(name);
67                             } else if (type == typeof(object[])) {
68                                 return new PrimitiveParameterExpression<object[]>(name);
69                             }
70                             break;
71                         case TypeCode.SByte: return new PrimitiveParameterExpression<SByte>(name);
72                         case TypeCode.Single: return new PrimitiveParameterExpression<Single>(name);
73                         case TypeCode.String: return new PrimitiveParameterExpression<String>(name);
74                         case TypeCode.UInt16: return new PrimitiveParameterExpression<UInt16>(name);
75                         case TypeCode.UInt32: return new PrimitiveParameterExpression<UInt32>(name);
76                         case TypeCode.UInt64: return new PrimitiveParameterExpression<UInt64>(name);
77                     }
78                 }
79             }
80
81             return new TypedParameterExpression(type, name);
82         }
83
84         /// <summary>
85         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
86         /// </summary>
87         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
88         public override Type Type {
89             get { return typeof(object); }
90         }
91
92         /// <summary>
93         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
94         /// </summary>
95         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
96         public sealed override ExpressionType NodeType {
97             get { return ExpressionType.Parameter; }
98         }
99
100         /// <summary>
101         /// The Name of the parameter or variable.
102         /// </summary>
103         public string Name {
104             get { return _name; }
105         }
106
107         /// <summary>
108         /// Indicates that this ParameterExpression is to be treated as a ByRef parameter.
109         /// </summary>
110         public bool IsByRef {
111             get {
112                 return GetIsByRef();
113             }
114         }
115
116         internal virtual bool GetIsByRef() {
117             return false;
118         }
119
120         /// <summary>
121         /// Dispatches to the specific visit method for this node type.
122         /// </summary>
123         protected internal override Expression Accept(ExpressionVisitor visitor) {
124             return visitor.VisitParameter(this);
125         }
126     }
127
128     /// <summary>
129     /// Specialized subclass to avoid holding onto the byref flag in a 
130     /// parameter expression.  This version always holds onto the expression
131     /// type explicitly and therefore derives from TypedParameterExpression.
132     /// </summary>
133     internal sealed class ByRefParameterExpression : TypedParameterExpression {
134         internal ByRefParameterExpression(Type type, string name)
135             : base(type, name) {
136         }
137
138         internal override bool GetIsByRef() {
139             return true;
140         }
141     }
142
143     /// <summary>
144     /// Specialized subclass which holds onto the type of the expression for
145     /// uncommon types.
146     /// </summary>
147     internal class TypedParameterExpression : ParameterExpression {
148         private readonly Type _paramType;
149
150         internal TypedParameterExpression(Type type, string name)
151             : base(name) {
152             _paramType = type;
153         }
154
155         public sealed override Type Type {
156             get { return _paramType; }
157         }
158     }
159
160     /// <summary>
161     /// Generic type to avoid needing explicit storage for primitive data types
162     /// which are commonly used.
163     /// </summary>
164     internal sealed class PrimitiveParameterExpression<T> : ParameterExpression {
165         internal PrimitiveParameterExpression(string name)
166             : base(name) {
167         }
168
169         public sealed override Type Type {
170             get { return typeof(T); }
171         }
172     }
173
174     public partial class Expression {
175
176         /// <summary>
177         /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree.
178         /// </summary>
179         /// <param name="type">The type of the parameter or variable.</param>
180         /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns>
181         public static ParameterExpression Parameter(Type type) {
182             return Parameter(type, null);
183         }
184
185         /// <summary>
186         /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree.
187         /// </summary>
188         /// <param name="type">The type of the parameter or variable.</param>
189         /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns>
190         public static ParameterExpression Variable(Type type) {
191             return Variable(type, null);
192         }
193
194         /// <summary>
195         /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree.
196         /// </summary>
197         /// <param name="type">The type of the parameter or variable.</param>
198         /// <param name="name">The name of the parameter or variable, used for debugging or pretty printing purpose only.</param>
199         /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns>
200         public static ParameterExpression Parameter(Type type, string name) {
201             ContractUtils.RequiresNotNull(type, "type");
202
203             if (type == typeof(void)) {
204                 throw Error.ArgumentCannotBeOfTypeVoid();
205             }
206
207             bool byref = type.IsByRef;
208             if (byref) {
209                 type = type.GetElementType();
210             }
211
212             return ParameterExpression.Make(type, name, byref);
213         }
214
215         /// <summary>
216         /// Creates a <see cref="ParameterExpression" /> node that can be used to identify a parameter or a variable in an expression tree.
217         /// </summary>
218         /// <param name="type">The type of the parameter or variable.</param>
219         /// <param name="name">The name of the parameter or variable, used for debugging or pretty printing purpose only.</param>
220         /// <returns>A <see cref="ParameterExpression" /> node with the specified name and type.</returns>
221         public static ParameterExpression Variable(Type type, string name) {
222             ContractUtils.RequiresNotNull(type, "type");
223             if (type == typeof(void)) throw Error.ArgumentCannotBeOfTypeVoid();
224             if (type.IsByRef) throw Error.TypeMustNotBeByRef();
225             return ParameterExpression.Make(type, name, false);
226         }
227     }
228 }