System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / NewArrayExpression.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.Collections.Generic;
18 using System.Collections.ObjectModel;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Runtime.CompilerServices;
22
23 #if SILVERLIGHT
24 using System.Core;
25 #endif
26
27 #if CLR2
28 namespace Microsoft.Scripting.Ast {
29 #else
30 namespace System.Linq.Expressions {
31 #endif
32
33     /// <summary>
34     /// Represents creating a new array and possibly initializing the elements of the new array.
35     /// </summary>
36 #if !SILVERLIGHT
37     [DebuggerTypeProxy(typeof(Expression.NewArrayExpressionProxy))]
38 #endif
39     public class NewArrayExpression : Expression {
40         private readonly ReadOnlyCollection<Expression> _expressions;
41         private readonly Type _type;
42
43         internal NewArrayExpression(Type type, ReadOnlyCollection<Expression> expressions) {
44             _expressions = expressions;
45             _type = type;
46         }
47
48         internal static NewArrayExpression Make(ExpressionType nodeType, Type type, ReadOnlyCollection<Expression> expressions) {
49             if (nodeType == ExpressionType.NewArrayInit) {
50                 return new NewArrayInitExpression(type, expressions);
51             } else {
52                 return new NewArrayBoundsExpression(type, expressions);
53             }
54         }
55
56         /// <summary>
57         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
58         /// </summary>
59         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
60         public sealed override Type Type {
61             get { return _type; }
62         }
63
64         /// <summary>
65         /// Gets the bounds of the array if the value of the <see cref="P:NodeType"/> property is NewArrayBounds, or the values to initialize the elements of the new array if the value of the <see cref="P:NodeType"/> property is NewArrayInit. 
66         /// </summary>
67         public ReadOnlyCollection<Expression> Expressions {
68             get { return _expressions; }
69         }
70
71         /// <summary>
72         /// Dispatches to the specific visit method for this node type.
73         /// </summary>
74         protected internal override Expression Accept(ExpressionVisitor visitor) {
75             return visitor.VisitNewArray(this);
76         }
77
78         /// <summary>
79         /// Creates a new expression that is like this one, but using the
80         /// supplied children. If all of the children are the same, it will
81         /// return this expression.
82         /// </summary>
83         /// <param name="expressions">The <see cref="Expressions" /> property of the result.</param>
84         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
85         public NewArrayExpression Update(IEnumerable<Expression> expressions) {
86             if (expressions == Expressions) {
87                 return this;
88             }
89             if (NodeType == ExpressionType.NewArrayInit) {
90                 return Expression.NewArrayInit(Type.GetElementType(), expressions);
91             }
92             return Expression.NewArrayBounds(Type.GetElementType(), expressions);
93         }
94     }
95
96     internal sealed class NewArrayInitExpression : NewArrayExpression {
97         internal NewArrayInitExpression(Type type, ReadOnlyCollection<Expression> expressions)
98             : base(type, expressions) {
99         }
100
101
102         /// <summary>
103         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
104         /// </summary>
105         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
106         public sealed override ExpressionType NodeType {
107             get { return ExpressionType.NewArrayInit; }
108         }
109     }
110
111     internal sealed class NewArrayBoundsExpression : NewArrayExpression {
112         internal NewArrayBoundsExpression(Type type, ReadOnlyCollection<Expression> expressions)
113             : base(type, expressions) {
114         }
115
116         /// <summary>
117         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
118         /// </summary>
119         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
120         public sealed override ExpressionType NodeType {
121             get { return ExpressionType.NewArrayBounds; }
122         }
123     }
124     
125     public partial class Expression {
126
127         #region NewArrayInit
128
129
130         /// <summary>
131         /// Creates a new array expression of the specified type from the provided initializers.
132         /// </summary>
133         /// <param name="type">A Type that represents the element type of the array.</param>
134         /// <param name="initializers">The expressions used to create the array elements.</param>
135         /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns>
136         public static NewArrayExpression NewArrayInit(Type type, params Expression[] initializers) {
137             return NewArrayInit(type, (IEnumerable<Expression>)initializers);
138         }
139
140         /// <summary>
141         /// Creates a new array expression of the specified type from the provided initializers.
142         /// </summary>
143         /// <param name="type">A Type that represents the element type of the array.</param>
144         /// <param name="initializers">The expressions used to create the array elements.</param>
145         /// <returns>An instance of the <see cref="NewArrayExpression"/>.</returns>
146         public static NewArrayExpression NewArrayInit(Type type, IEnumerable<Expression> initializers) {
147             ContractUtils.RequiresNotNull(type, "type");
148             ContractUtils.RequiresNotNull(initializers, "initializers");
149             if (type.Equals(typeof(void))) {
150                 throw Error.ArgumentCannotBeOfTypeVoid();
151             }
152
153             ReadOnlyCollection<Expression> initializerList = initializers.ToReadOnly();
154
155             Expression[] newList = null;
156             for (int i = 0, n = initializerList.Count; i < n; i++) {
157                 Expression expr = initializerList[i];
158                 RequiresCanRead(expr, "initializers");
159
160                 if (!TypeUtils.AreReferenceAssignable(type, expr.Type)) {
161                     if (!TryQuote(type, ref expr)){
162                         throw Error.ExpressionTypeCannotInitializeArrayType(expr.Type, type);
163                     }
164                     if (newList == null) {
165                         newList = new Expression[initializerList.Count];
166                         for (int j = 0; j < i; j++) {
167                             newList[j] = initializerList[j];
168                         }
169                     }
170                 }
171                 if (newList != null) {
172                     newList[i] = expr;
173                 }
174             }
175             if (newList != null) {
176                 initializerList = new TrueReadOnlyCollection<Expression>(newList);
177             }
178
179             return NewArrayExpression.Make(ExpressionType.NewArrayInit, type.MakeArrayType(), initializerList);
180         }
181
182         #endregion
183
184         #region NewArrayBounds
185
186
187         /// <summary>
188         /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. 
189         /// </summary>
190         /// <param name="type">A <see cref="Type"/> that represents the element type of the array.</param>
191         /// <param name="bounds">An array that contains Expression objects to use to populate the Expressions collection.</param>
192         /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="P:NodeType"/> property equal to type and the <see cref="P:Expressions"/> property set to the specified value.</returns>
193         public static NewArrayExpression NewArrayBounds(Type type, params Expression[] bounds) {
194             return NewArrayBounds(type, (IEnumerable<Expression>)bounds);
195         }
196
197
198         /// <summary>
199         /// Creates a <see cref="NewArrayExpression"/> that represents creating an array that has a specified rank. 
200         /// </summary>
201         /// <param name="type">A <see cref="Type"/> that represents the element type of the array.</param>
202         /// <param name="bounds">An IEnumerable{T} that contains Expression objects to use to populate the Expressions collection.</param>
203         /// <returns>A <see cref="NewArrayExpression"/> that has the <see cref="P:NodeType"/> property equal to type and the <see cref="P:Expressions"/> property set to the specified value.</returns>
204         public static NewArrayExpression NewArrayBounds(Type type, IEnumerable<Expression> bounds) {
205             ContractUtils.RequiresNotNull(type, "type");
206             ContractUtils.RequiresNotNull(bounds, "bounds");
207
208             if (type.Equals(typeof(void))) {
209                 throw Error.ArgumentCannotBeOfTypeVoid();
210             }
211
212             ReadOnlyCollection<Expression> boundsList = bounds.ToReadOnly();
213
214             int dimensions = boundsList.Count;
215             if (dimensions <= 0) throw Error.BoundsCannotBeLessThanOne();
216
217             for (int i = 0; i < dimensions; i++) {
218                 Expression expr = boundsList[i];
219                 RequiresCanRead(expr, "bounds");
220                 if (!TypeUtils.IsInteger(expr.Type)) {
221                     throw Error.ArgumentMustBeInteger();
222                 }
223             }
224
225             Type arrayType;
226             if (dimensions == 1) {
227                 //To get a vector, need call Type.MakeArrayType(). 
228                 //Type.MakeArrayType(1) gives a non-vector array, which will cause type check error.
229                 arrayType = type.MakeArrayType();
230             } else {
231                 arrayType = type.MakeArrayType(dimensions);
232             }
233
234             return NewArrayExpression.Make(ExpressionType.NewArrayBounds, arrayType, bounds.ToReadOnly());
235         }
236
237         #endregion
238
239     }
240 }