This repository has been archived by the owner on Jun 11, 2021. It is now read-only.
forked from dotnet/dotNext
-
Notifications
You must be signed in to change notification settings - Fork 1
/
WhileExpression.cs
123 lines (109 loc) · 5.06 KB
/
WhileExpression.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
using System;
using System.Linq.Expressions;
namespace DotNext.Linq.Expressions
{
/// <summary>
/// Represents <c>while</c> loop expression.
/// </summary>
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/while">while Statement</seealso>
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/do">do-while Statement</seealso>
public sealed class WhileExpression : CustomExpression, ILoopLabels
{
/// <summary>
/// Represents constructor of the loop body.
/// </summary>
/// <param name="continueLabel">A label that can be used to produce <see cref="Expression.Continue(LabelTarget)"/> expression.</param>
/// <param name="breakLabel">A label that can be used to produce <see cref="Expression.Break(LabelTarget)"/> expression.</param>
/// <returns>The loop body.</returns>
public delegate Expression Statement(LabelTarget continueLabel, LabelTarget breakLabel);
private readonly bool conditionFirst;
private Expression? body;
internal WhileExpression(Expression test, LabelTarget? continueLabel, LabelTarget? breakLabel, bool checkConditionFirst)
{
if (test is null)
throw new ArgumentNullException(nameof(test));
else if (test.Type != typeof(bool))
throw new ArgumentException(ExceptionMessages.TypeExpected<bool>(), nameof(test));
Test = test;
conditionFirst = checkConditionFirst;
ContinueLabel = continueLabel ?? Label(typeof(void), "continue");
BreakLabel = breakLabel ?? Label(typeof(void), "break");
}
private WhileExpression(Expression test, bool checkConditionFirst)
: this(test, null, null, checkConditionFirst)
{
}
/// <summary>
/// Creates a new loop expression.
/// </summary>
/// <param name="test">The loop condition.</param>
/// <param name="body">The delegate that is used to construct loop body.</param>
/// <param name="checkConditionFirst"><see langword="true"/> to check condition before loop body; <see langword="false"/> to use do-while style.</param>
/// <returns>The constructed loop expression.</returns>
public static WhileExpression Create(Expression test, Statement body, bool checkConditionFirst)
{
var result = new WhileExpression(test, checkConditionFirst);
result.Body = body(result.ContinueLabel, result.BreakLabel);
return result;
}
/// <summary>
/// Creates a new loop expression.
/// </summary>
/// <param name="test">The loop condition.</param>
/// <param name="body">The loop body.</param>
/// <param name="checkConditionFirst"><see langword="true"/> to check condition before loop body; <see langword="false"/> to use do-while style.</param>
/// <returns>The constructed loop expression.</returns>
public static WhileExpression Create(Expression test, Expression body, bool checkConditionFirst)
=> new(test, checkConditionFirst) { Body = body };
/// <summary>
/// Gets label that is used by the loop body as a break statement target.
/// </summary>
public LabelTarget BreakLabel { get; }
/// <summary>
/// Gets label that is used by the loop body as a continue statement target.
/// </summary>
public LabelTarget ContinueLabel { get; }
/// <summary>
/// Gets loop condition.
/// </summary>
public Expression Test { get; }
/// <summary>
/// Gets body of the loop.
/// </summary>
public Expression Body
{
get => body ?? Empty();
internal set => body = value;
}
/// <summary>
/// Always returns <see cref="void"/>.
/// </summary>
public override Type Type => typeof(void);
/// <summary>
/// Reconstructs loop expression with a new body.
/// </summary>
/// <param name="body">The body of the loop.</param>
/// <returns>Updated loop expression.</returns>
public WhileExpression Update(Expression body) => new(Test, conditionFirst) { Body = body };
/// <summary>
/// Translates this expression into predefined set of expressions
/// using Lowering technique.
/// </summary>
/// <returns>Translated expression.</returns>
public override Expression Reduce()
{
Expression loopBody;
if (conditionFirst)
{
loopBody = Condition(Test, Body, Goto(BreakLabel), typeof(void));
return Loop(loopBody, BreakLabel, ContinueLabel);
}
else
{
var condition = Condition(Test, Empty(), Goto(BreakLabel), typeof(void));
loopBody = Block(typeof(void), Body, Label(ContinueLabel), condition);
return Loop(loopBody, BreakLabel);
}
}
}
}