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