-
Notifications
You must be signed in to change notification settings - Fork 1
/
ControlFlow.cs
143 lines (127 loc) · 7.65 KB
/
ControlFlow.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using JetBrains.Annotations;
namespace ILGeneratorExtensions
{
/// <summary>
/// Contains extension methods for controlling the flow of the method
/// </summary>
public static class ControlFlow
{
/// <summary>
/// Branch unconditionally to the given label
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="label">The label to branch to</param>
[PublicAPI]
public static ILGenerator BranchTo(this ILGenerator generator, Label label) => generator.FluentEmit(OpCodes.Br, label);
/// <summary>
/// Branch unconditionally to the given label
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labelName">The name of the fluently-specified label</param>
[PublicAPI]
public static ILGenerator BranchTo(this ILGenerator generator, string labelName)
=> generator.BranchTo(generator.GetOrCreateLabel(labelName));
/// <summary>
/// Branch unconditionally to the given label
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="label">The label to branch to</param>
[PublicAPI]
public static ILGenerator BranchToShortForm(this ILGenerator generator, Label label) => generator.FluentEmit(OpCodes.Br_S, label);
/// <summary>
/// Branch unconditionally to the given label
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labelName">The name of the fluently-specified label</param>
[PublicAPI]
public static ILGenerator BranchToShortForm(this ILGenerator generator, string labelName)
=> generator.BranchToShortForm(generator.GetOrCreateLabel(labelName));
/// <summary>
/// Pops an integer value from the evaluation stack and branches to the corresponding zero-indexed label in the provided list, continuing to the next instruction if the value is outside the valid range
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labels">The labels to form a jump table from</param>
[PublicAPI]
public static ILGenerator Switch(this ILGenerator generator, params Label[] labels) => generator.FluentEmit(OpCodes.Switch, labels);
/// <summary>
/// Pops an integer value from the evaluation stack and branches to the corresponding zero-indexed label in the provided list, continuing to the next instruction if the value is outside the valid range
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labelNames">The names of the fluently-specified labels to form a jump table from</param>
[PublicAPI]
public static ILGenerator Switch(this ILGenerator generator, params string[] labelNames)
=> generator.Switch(labelNames.Select(generator.GetOrCreateLabel).ToArray());
/// <summary>
/// Branch to the given label, clearing the evaluation stack; can be used to leave a protected region
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="label">The label to branch to</param>
[PublicAPI]
public static ILGenerator Leave(this ILGenerator generator, Label label) => generator.FluentEmit(OpCodes.Leave, label);
/// <summary>
/// Branch to the given label, clearing the evaluation stack; can be used to leave a protected region
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labelName">The name of the fluently-specified label</param>
[PublicAPI]
public static ILGenerator Leave(this ILGenerator generator, string labelName)
=> generator.Leave(generator.GetOrCreateLabel(labelName));
/// <summary>
/// Branch to the given label, clearing the evaluation stack; can be used to leave a protected region
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="label">The label to branch to</param>
[PublicAPI]
public static ILGenerator LeaveShortForm(this ILGenerator generator, Label label) => generator.FluentEmit(OpCodes.Leave_S, label);
/// <summary>
/// Branch to the given label, clearing the evaluation stack; can be used to leave a protected region
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="labelName">The name of the fluently-specified label</param>
[PublicAPI]
public static ILGenerator LeaveShortForm(this ILGenerator generator, string labelName)
=> generator.LeaveShortForm(generator.GetOrCreateLabel(labelName));
/// <summary>
/// Pops a reference to an exception off the evaluation stack and throws it
/// </summary>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator Throw(this ILGenerator generator) => generator.FluentEmit(OpCodes.Throw);
/// <summary>
/// Throws an exception of the given type, using the default constructor
/// </summary>
/// <typeparam name="T">The type of the exception to throw</typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
[PublicAPI]
public static ILGenerator Throw<T>(this ILGenerator generator) where T : Exception, new()
{
generator.ThrowException(typeof (T));
return generator;
}
[PublicAPI]
private static readonly Type[] StringTypeArray = { typeof (string) };
/// <summary>
/// Throws an exception of the given type with the given message
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="generator">The <see cref="T:System.Reflection.Emit.ILGenerator" /> to emit instructions from</param>
/// <param name="message">The message to give the exception</param>
/// <exception cref="InvalidOperationException">Exception type <typeparamref name="T"/> does not have a public constructor taking only a string</exception>
[PublicAPI]
public static ILGenerator Throw<T>(this ILGenerator generator, string message) where T : Exception
{
var constructor = typeof (T).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, StringTypeArray, null);
if (constructor == null)
{
throw new InvalidOperationException("Exception type " + typeof (T).Name + " does not have a public constructor taking only a string");
}
return generator.LoadString(message)
.NewObject(constructor)
.Throw();
}
}
}