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 / GotoExpression.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     /// <summary>
30     /// Specifies what kind of jump this <see cref="GotoExpression"/> represents.
31     /// </summary>
32     public enum GotoExpressionKind {
33         /// <summary>
34         /// A <see cref="GotoExpression"/> that represents a jump to some location.
35         /// </summary>
36         Goto,
37         /// <summary>
38         /// A <see cref="GotoExpression"/> that represents a return statement.
39         /// </summary>
40         Return,
41         /// <summary>
42         /// A <see cref="GotoExpression"/> that represents a break statement.
43         /// </summary>
44         Break,
45         /// <summary>
46         /// A <see cref="GotoExpression"/> that represents a continue statement.
47         /// </summary>
48         Continue,
49     }
50
51     /// <summary>
52     /// Represents an unconditional jump. This includes return statements, break and continue statements, and other jumps.
53     /// </summary>
54 #if !SILVERLIGHT
55     [DebuggerTypeProxy(typeof(Expression.GotoExpressionProxy))]
56 #endif
57     public sealed class GotoExpression : Expression {
58         private readonly GotoExpressionKind _kind;
59         private readonly Expression _value;
60         private readonly LabelTarget _target;
61         private readonly Type _type;
62
63         internal GotoExpression(GotoExpressionKind kind, LabelTarget target, Expression value, Type type) {
64             _kind = kind;
65             _value = value;
66             _target = target;
67             _type = type;
68         }
69
70         /// <summary>
71         /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
72         /// </summary>
73         /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
74         public sealed override Type Type {
75             get { return _type; }
76         }
77
78         /// <summary>
79         /// Returns the node type of this <see cref="Expression" />. (Inherited from <see cref="Expression" />.)
80         /// </summary>
81         /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
82         public sealed override ExpressionType NodeType {
83             get { return ExpressionType.Goto; }
84         }
85
86         /// <summary>
87         /// The value passed to the target, or null if the target is of type
88         /// System.Void.
89         /// </summary>
90         public Expression Value {
91             get { return _value; }
92         }
93
94         /// <summary>
95         /// The target label where this node jumps to.
96         /// </summary>
97         public LabelTarget Target {
98             get { return _target; }
99         }
100
101         /// <summary>
102         /// The kind of the goto. For information purposes only.
103         /// </summary>
104         public GotoExpressionKind Kind {
105             get { return _kind; }
106         }
107
108         /// <summary>
109         /// Dispatches to the specific visit method for this node type.
110         /// </summary>
111         protected internal override Expression Accept(ExpressionVisitor visitor) {
112             return visitor.VisitGoto(this);
113         }
114
115         /// <summary>
116         /// Creates a new expression that is like this one, but using the
117         /// supplied children. If all of the children are the same, it will
118         /// return this expression.
119         /// </summary>
120         /// <param name="target">The <see cref="Target" /> property of the result.</param>
121         /// <param name="value">The <see cref="Value" /> property of the result.</param>
122         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
123         public GotoExpression Update(LabelTarget target, Expression value) {
124             if (target == Target && value == Value) {
125                 return this;
126             }
127             return Expression.MakeGoto(Kind, target, value, Type);
128         }
129     }
130
131     public partial class Expression {
132         /// <summary>
133         /// Creates a <see cref="GotoExpression"/> representing a break statement.
134         /// </summary>
135         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
136         /// <returns>
137         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Break, 
138         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, and a null value to be passed to the target label upon jumping.
139         /// </returns>
140         public static GotoExpression Break(LabelTarget target) {
141             return MakeGoto(GotoExpressionKind.Break, target, null, typeof(void));
142         }
143
144         /// <summary>
145         /// Creates a <see cref="GotoExpression"/> representing a break statement. The value passed to the label upon jumping can be specified.
146         /// </summary>
147         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
148         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
149         /// <returns>
150         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Break, 
151         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
152         /// and <paramref name="value"/> to be passed to the target label upon jumping.
153         /// </returns>
154         public static GotoExpression Break(LabelTarget target, Expression value) {
155             return MakeGoto(GotoExpressionKind.Break, target, value, typeof(void));
156         }
157
158         /// <summary>
159         /// Creates a <see cref="GotoExpression"/> representing a break statement with the specified type.
160         /// </summary>
161         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
162         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
163         /// <returns>
164         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Break, 
165         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
166         /// and the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>.
167         /// </returns>
168         public static GotoExpression Break(LabelTarget target, Type type) {
169             return MakeGoto(GotoExpressionKind.Break, target, null, type);
170         }
171
172         /// <summary>
173         /// Creates a <see cref="GotoExpression"/> representing a break statement with the specified type. 
174         /// The value passed to the label upon jumping can be specified.
175         /// </summary>
176         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
177         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
178         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
179         /// <returns>
180         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Break, 
181         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
182         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
183         /// and <paramref name="value"/> to be passed to the target label upon jumping.
184         /// </returns>
185         public static GotoExpression Break(LabelTarget target, Expression value, Type type) {
186             return MakeGoto(GotoExpressionKind.Break, target, value, type);
187         }
188
189         /// <summary>
190         /// Creates a <see cref="GotoExpression"/> representing a continue statement.
191         /// </summary>
192         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
193         /// <returns>
194         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, 
195         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
196         /// and a null value to be passed to the target label upon jumping.
197         /// </returns>
198         public static GotoExpression Continue(LabelTarget target) {
199             return MakeGoto(GotoExpressionKind.Continue, target, null, typeof(void));
200         }
201
202         /// <summary>
203         /// Creates a <see cref="GotoExpression"/> representing a continue statement with the specified type.
204         /// </summary>
205         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
206         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
207         /// <returns>
208         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, 
209         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
210         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
211         /// and a null value to be passed to the target label upon jumping.
212         /// </returns>
213         public static GotoExpression Continue(LabelTarget target, Type type) {
214             return MakeGoto(GotoExpressionKind.Continue, target, null, type);
215         }
216
217         /// <summary>
218         /// Creates a <see cref="GotoExpression"/> representing a return statement.
219         /// </summary>
220         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
221         /// <returns>
222         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Return, 
223         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
224         /// and a null value to be passed to the target label upon jumping.
225         /// </returns>
226         public static GotoExpression Return(LabelTarget target) {
227             return MakeGoto(GotoExpressionKind.Return, target, null, typeof(void));
228         }
229
230         /// <summary>
231         /// Creates a <see cref="GotoExpression"/> representing a return statement with the specified type.
232         /// </summary>
233         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
234         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
235         /// <returns>
236         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Return, 
237         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
238         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
239         /// and a null value to be passed to the target label upon jumping.
240         /// </returns>
241         public static GotoExpression Return(LabelTarget target, Type type) {
242             return MakeGoto(GotoExpressionKind.Return, target, null, type);
243         }
244
245         /// <summary>
246         /// Creates a <see cref="GotoExpression"/> representing a return statement. The value passed to the label upon jumping can be specified.
247         /// </summary>
248         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
249         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
250         /// <returns>
251         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, 
252         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
253         /// and <paramref name="value"/> to be passed to the target label upon jumping.
254         /// </returns>
255         public static GotoExpression Return(LabelTarget target, Expression value) {
256             return MakeGoto(GotoExpressionKind.Return, target, value, typeof(void));
257         }
258
259         /// <summary>
260         /// Creates a <see cref="GotoExpression"/> representing a return statement with the specified type. 
261         /// The value passed to the label upon jumping can be specified.
262         /// </summary>
263         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
264         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
265         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
266         /// <returns>
267         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Continue, 
268         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
269         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
270         /// and <paramref name="value"/> to be passed to the target label upon jumping.
271         /// </returns>
272         public static GotoExpression Return(LabelTarget target, Expression value, Type type) {
273             return MakeGoto(GotoExpressionKind.Return, target, value, type);
274         }
275         
276         /// <summary>
277         /// Creates a <see cref="GotoExpression"/> representing a goto.
278         /// </summary>
279         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
280         /// <returns>
281         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, 
282         /// the <see cref="P:GotoExpression.Target"/> property set to the specified value, 
283         /// and a null value to be passed to the target label upon jumping.
284         /// </returns>
285         public static GotoExpression Goto(LabelTarget target) {
286             return MakeGoto(GotoExpressionKind.Goto, target, null, typeof(void));
287         }
288
289         /// <summary>
290         /// Creates a <see cref="GotoExpression"/> representing a goto with the specified type.
291         /// </summary>
292         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
293         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
294         /// <returns>
295         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, 
296         /// the <see cref="P:GotoExpression.Target"/> property set to the specified value, 
297         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
298         /// and a null value to be passed to the target label upon jumping.
299         /// </returns>
300         public static GotoExpression Goto(LabelTarget target, Type type) {
301             return MakeGoto(GotoExpressionKind.Goto, target, null, type);
302         }
303
304         /// <summary>
305         /// Creates a <see cref="GotoExpression"/> representing a goto. The value passed to the label upon jumping can be specified.
306         /// </summary>
307         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
308         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
309         /// <returns>
310         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, 
311         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
312         /// and <paramref name="value"/> to be passed to the target label upon jumping.
313         /// </returns>
314         public static GotoExpression Goto(LabelTarget target, Expression value) {
315             return MakeGoto(GotoExpressionKind.Goto, target, value, typeof(void));
316         }
317
318         /// <summary>
319         /// Creates a <see cref="GotoExpression"/> representing a goto with the specified type.
320         /// The value passed to the label upon jumping can be specified.
321         /// </summary>
322         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
323         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
324         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
325         /// <returns>
326         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to Goto, 
327         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
328         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
329         /// and <paramref name="value"/> to be passed to the target label upon jumping.
330         /// </returns>
331         public static GotoExpression Goto(LabelTarget target, Expression value, Type type) {
332             return MakeGoto(GotoExpressionKind.Goto, target, value, type);
333         }
334
335         /// <summary>
336         /// Creates a <see cref="GotoExpression"/> representing a jump of the specified <see cref="GotoExpressionKind"/>.
337         /// The value passed to the label upon jumping can also be specified.
338         /// </summary>
339         /// <param name="kind">The <see cref="GotoExpressionKind"/> of the <see cref="GotoExpression"/>.</param>
340         /// <param name="target">The <see cref="LabelTarget"/> that the <see cref="GotoExpression"/> will jump to.</param>
341         /// <param name="value">The value that will be passed to the associated label upon jumping.</param>
342         /// <param name="type">An <see cref="System.Type"/> to set the <see cref="P:Expression.Type"/> property equal to.</param>
343         /// <returns>
344         /// A <see cref="GotoExpression"/> with <see cref="P:GotoExpression.Kind"/> equal to <paramref name="kind"/>, 
345         /// the <see cref="P:GotoExpression.Target"/> property set to <paramref name="target"/>, 
346         /// the <see cref="P:Expression.Type"/> property set to <paramref name="type"/>,
347         /// and <paramref name="value"/> to be passed to the target label upon jumping.
348         /// </returns>
349         public static GotoExpression MakeGoto(GotoExpressionKind kind, LabelTarget target, Expression value, Type type) {
350             ValidateGoto(target, ref value, "target", "value");
351             return new GotoExpression(kind, target, value, type);
352         }
353
354         private static void ValidateGoto(LabelTarget target, ref Expression value, string targetParameter, string valueParameter) {
355             ContractUtils.RequiresNotNull(target, targetParameter);
356             if (value == null) {
357                 if (target.Type != typeof(void)) throw Error.LabelMustBeVoidOrHaveExpression();
358             } else {
359                 ValidateGotoType(target.Type, ref value, valueParameter);
360             }
361         }
362
363         // Standard argument validation, taken from ValidateArgumentTypes
364         private static void ValidateGotoType(Type expectedType, ref Expression value, string paramName) {
365             RequiresCanRead(value, paramName);
366             if (expectedType != typeof(void)) {
367                 if (!TypeUtils.AreReferenceAssignable(expectedType, value.Type)) {
368                     // C# autoquotes return values, so we'll do that here
369                     if (!TryQuote(expectedType, ref value)) {
370                         throw Error.ExpressionTypeDoesNotMatchLabel(value.Type, expectedType);
371                     }
372                 }
373             }
374         }
375
376     }
377 }