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
/
NullCoalescingAssignmentExpression.cs
111 lines (97 loc) · 4.46 KB
/
NullCoalescingAssignmentExpression.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
using System;
using System.Linq.Expressions;
namespace DotNext.Linq.Expressions
{
/// <summary>
/// Represents null-coalescing assignment operator.
/// </summary>
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/null-coalescing-assignment">Null-coalescing assignment.</seealso>
public sealed class NullCoalescingAssignmentExpression : CustomExpression
{
internal NullCoalescingAssignmentExpression(Expression left, Expression right)
{
if (left is null)
throw new ArgumentNullException(nameof(left));
if (right is null)
throw new ArgumentNullException(nameof(right));
if (!left.Type.IsAssignableFrom(right.Type))
throw new ArgumentException(ExceptionMessages.TypeExpected(left.Type), nameof(right));
Left = left;
Right = right;
}
/// <summary>
/// Initializes a new assignment expression.
/// </summary>
/// <param name="left">The left operand of the assignment.</param>
/// <param name="right">The right operand of the assignment.</param>
/// <exception cref="ArgumentException"><paramref name="right"/> is not assignable to <paramref name="left"/>.</exception>
public NullCoalescingAssignmentExpression(ParameterExpression left, Expression right)
: this(left.As<Expression>(), right)
{
}
/// <summary>
/// Initializes a new assignment expression.
/// </summary>
/// <param name="left">The left operand of the assignment.</param>
/// <param name="right">The right operand of the assignment.</param>
/// <exception cref="ArgumentException"><paramref name="right"/> is not assignable to <paramref name="left"/>.</exception>
public NullCoalescingAssignmentExpression(MemberExpression left, Expression right)
: this(left.As<Expression>(), right)
{
}
/// <summary>
/// Initializes a new assignment expression.
/// </summary>
/// <param name="left">The left operand of the assignment.</param>
/// <param name="right">The right operand of the assignment.</param>
/// <exception cref="ArgumentException"><paramref name="right"/> is not assignable to <paramref name="left"/>.</exception>
public NullCoalescingAssignmentExpression(IndexExpression left, Expression right)
: this(left.As<Expression>(), right)
{
}
/// <summary>
/// Gets the left operand of the assignment operation.
/// </summary>
public Expression Left { get; }
/// <summary>
/// Gets the right operand of the assignment operation.
/// </summary>
public Expression Right { get; }
/// <summary>
/// Gets result type of asynchronous operation.
/// </summary>
public override Type Type => Left.Type;
/// <summary>
/// Translates this expression into predefined set of expressions
/// using Lowering technique.
/// </summary>
/// <returns>Translated expression.</returns>
public override Expression Reduce()
{
if (Left.Type.IsValueType && Nullable.GetUnderlyingType(Left.Type) is null || Left.Type.IsPrimitive || Left.Type.IsPointer)
return Left;
if (Left is ParameterExpression localVar)
return Build(localVar, Right);
localVar = Variable(Left.Type);
return Block(
Left.Type,
new[] { localVar },
Assign(localVar, Left),
Assign(Left, Build(localVar, Right)),
localVar);
static Expression Build(ParameterExpression left, Expression right)
=> Coalesce(left, Assign(left, right));
}
/// <summary>
/// Visit children expressions.
/// </summary>
/// <param name="visitor">Expression visitor.</param>
/// <returns>Potentially modified expression if one of children expressions is modified during visit.</returns>
protected override Expression VisitChildren(ExpressionVisitor visitor)
{
var left = visitor.Visit(Left);
var right = visitor.Visit(Right);
return ReferenceEquals(left, Left) && ReferenceEquals(right, Right) ? this : new NullCoalescingAssignmentExpression(left, right);
}
}
}