1
+ using System ;
2
+ using System . CodeDom ;
3
+ using System . Linq ;
4
+ using Diesel . Parsing ;
5
+ using Diesel . Parsing . CSharp ;
6
+
7
+ namespace Diesel . CodeGeneration
8
+ {
9
+ public class EqualityMethodsGenerator
10
+ {
11
+ /// <summary>
12
+ /// Produce an expression that compares two properties by value.
13
+ /// </summary>
14
+ public static CodeExpression ComparePropertyValueEqualityExpression ( PropertyDeclaration property , string otherVariableName )
15
+ {
16
+ return ComparePropertyValueEqualityExpression ( ( dynamic ) property . Type , property . Name , otherVariableName ) ;
17
+ }
18
+
19
+ private static CodeBinaryOperatorExpression ComparePropertyValueEqualityExpression ( SimpleType propertyType , String propertyName , String otherVariableName )
20
+ {
21
+ return CompareValueEquality ( propertyName , otherVariableName ) ;
22
+ }
23
+
24
+ private static CodeBinaryOperatorExpression ComparePropertyValueEqualityExpression ( StringReferenceType propertyType , String propertyName , String otherVariableName )
25
+ {
26
+ return CompareValueEquality ( propertyName , otherVariableName ) ;
27
+ }
28
+
29
+ /// <summary>
30
+ /// this.PropertyName == other.PropertyName
31
+ /// </summary>
32
+ private static CodeBinaryOperatorExpression CompareValueEquality ( string propertyName , string otherVariableName )
33
+ {
34
+ return new CodeBinaryOperatorExpression (
35
+ ThisPropertyReference ( propertyName ) ,
36
+ CodeBinaryOperatorType . ValueEquality ,
37
+ OtherPropertyReference ( propertyName , otherVariableName ) ) ;
38
+ }
39
+
40
+ /// <summary>
41
+ /// Object.Equals(a.Property, b.Property)
42
+ /// </summary>
43
+ private static CodeExpression CompareObjectEquality ( string propertyName , string otherVariableName )
44
+ {
45
+ return new CodeMethodInvokeExpression (
46
+ new CodeTypeReferenceExpression ( typeof ( Object ) ) ,
47
+ "Equals" ,
48
+ ThisPropertyReference ( propertyName ) ,
49
+ OtherPropertyReference ( propertyName , otherVariableName ) ) ;
50
+ }
51
+
52
+ private static CodeBinaryOperatorExpression ComparePropertyValueEqualityExpression ( NullableType propertyType , String propertyName , String otherVariableName )
53
+ {
54
+ return CompareValueEquality ( propertyName , otherVariableName ) ;
55
+ }
56
+
57
+ /// <summary>
58
+ /// (this.Property.Length == other.Property.Length)
59
+ /// && Enumerable.Zip(a, b, (a, b) => a == b).All(areEqual => areEqual);
60
+ /// </summary>
61
+ private static CodeBinaryOperatorExpression ComparePropertyValueEqualityExpression ( ArrayType propertyType ,
62
+ String propertyName ,
63
+ String otherVariableName )
64
+ {
65
+ // TODO: this should probably be a warning in the model
66
+ if ( propertyType . RankSpecifiers . Ranks . Count ( ) > 1 )
67
+ throw new InvalidOperationException (
68
+ "Cannot generate equality for Array Types with more than one rank-specifier." ) ;
69
+ var rankSpecifier = propertyType . RankSpecifiers . Ranks . Single ( ) ;
70
+ if ( rankSpecifier . Dimensions > 1 )
71
+ throw new InvalidOperationException (
72
+ "Cannot generate equality for Array Type with more than one dimension" ) ;
73
+
74
+ // (this.Property.Length == other.Property.Length)
75
+ // && Enumerable.Zip(a, b, (a, b) => Object.Equals(a, b)).All(areEqual => areEqual);
76
+
77
+ var thisPropertyReference = ThisPropertyReference ( propertyName ) ;
78
+ var otherPropertyReference = OtherPropertyReference ( propertyName , otherVariableName ) ;
79
+
80
+ var sameArrayLength = new CodeBinaryOperatorExpression (
81
+ new CodePropertyReferenceExpression ( thisPropertyReference , "Length" ) ,
82
+ CodeBinaryOperatorType . ValueEquality ,
83
+ new CodePropertyReferenceExpression ( otherPropertyReference , "Length" ) ) ;
84
+
85
+ var zipExpression = new CodeMethodInvokeExpression (
86
+ new CodeMethodReferenceExpression (
87
+ new CodeTypeReferenceExpression ( typeof ( System . Linq . Enumerable ) ) ,
88
+ "Zip" ) ,
89
+ thisPropertyReference ,
90
+ otherPropertyReference ,
91
+ new CodeSnippetExpression ( "(a, b) => Object.Equals(a,b)" ) ) ;
92
+
93
+ var zipPairwiseEquality =
94
+ new CodeMethodInvokeExpression (
95
+ new CodeMethodReferenceExpression (
96
+ new CodeTypeReferenceExpression ( typeof ( System . Linq . Enumerable ) ) ,
97
+ "All" ) ,
98
+ zipExpression ,
99
+ new CodeSnippetExpression ( "areEqual => areEqual" )
100
+ ) ;
101
+
102
+ return new CodeBinaryOperatorExpression ( sameArrayLength ,
103
+ CodeBinaryOperatorType . BooleanAnd , zipPairwiseEquality ) ;
104
+ }
105
+
106
+ private static CodePropertyReferenceExpression OtherPropertyReference ( string propertyName , string otherVariableName )
107
+ {
108
+ return new CodePropertyReferenceExpression ( new CodeVariableReferenceExpression ( otherVariableName ) , propertyName ) ;
109
+ }
110
+
111
+ private static CodePropertyReferenceExpression ThisPropertyReference ( string propertyName )
112
+ {
113
+ return new CodePropertyReferenceExpression ( new CodeThisReferenceExpression ( ) , propertyName ) ;
114
+ }
115
+
116
+ private static CodeExpression ComparePropertyValueEqualityExpression ( TypeNameTypeNode propertyType , String propertyName , String otherVariableName )
117
+ {
118
+ return CompareObjectEquality ( propertyName , otherVariableName ) ;
119
+ }
120
+ }
121
+ }
0 commit comments