Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / ExpressionUtil / ExpressionFingerprint.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc.ExpressionUtil {\r
14     using System;\r
15     using System.Collections.Generic;\r
16     using System.Collections.ObjectModel;\r
17     using System.Linq;\r
18     using System.Linq.Expressions;\r
19 \r
20     // Expression fingerprint class\r
21     // Contains information used for generalizing, comparing, and recreating Expression instances\r
22     //\r
23     // Since Expression objects are immutable and are recreated for every invocation of an expression\r
24     // helper method, they can't be compared directly. Fingerprinting Expression objects allows\r
25     // information about them to be abstracted away, and the fingerprints can be directly compared.\r
26     // Consider the process of fingerprinting that all values (parameters, constants, etc.) are hoisted\r
27     // and replaced with dummies. What remains can be decomposed into a sequence of operations on specific\r
28     // types and specific inputs.\r
29     //\r
30     // Some sample fingerprints:\r
31     //\r
32     // 2 + 4 -> OP_ADD(CONST:int, CONST:int):int\r
33     // 2 + 8 -> OP_ADD(CONST:int, CONST:int):int\r
34     // 2.0 + 4.0 -> OP_ADD(CONST:double, CONST:double):double\r
35     //\r
36     // 2 + 4 and 2 + 8 have the same fingerprint, but 2.0 + 4.0 has a different fingerprint since its\r
37     // underlying types differ.\r
38     //\r
39     // "Hello " + "world" -> OP_ADD(CONST:string, CONST:string):string\r
40     // "Hello " + {model} -> OP_ADD(CONST:string, PARAM:string):string\r
41     //\r
42     // These string concatenations have different fingerprints since the inputs are provided differently:\r
43     // one is a hoisted local, the other is a parameter.\r
44     //\r
45     // ({model} ?? "sample").Length -> MEMBER_ACCESS(String.Length, OP_COALESCE(PARAM:string, CONST:string):string):int\r
46     // ({model} ?? "other sample").Length -> MEMBER_ACCESS(String.Length, OP_COALESCE(PARAM:string, CONST:string):string):int\r
47     //\r
48     // These expressions have the same fingerprint.\r
49     internal abstract class ExpressionFingerprint {\r
50 \r
51         protected ExpressionFingerprint(Expression expression) {\r
52             // since the fingerprints are cached potentially forever, don't keep a reference\r
53             // to the original expression\r
54 \r
55             NodeType = expression.NodeType;\r
56             Type = expression.Type;\r
57         }\r
58 \r
59         // the type of expression node, e.g. OP_ADD, MEMBER_ACCESS, etc.\r
60         public ExpressionType NodeType {\r
61             get;\r
62             private set;\r
63         }\r
64 \r
65         // the CLR type resulting from this expression, e.g. int, string, etc.\r
66         public Type Type {\r
67             get;\r
68             private set;\r
69         }\r
70 \r
71         internal virtual void AddToHashCodeCombiner(HashCodeCombiner combiner) {\r
72             combiner.AddObject(NodeType);\r
73             combiner.AddObject(Type);\r
74         }\r
75 \r
76         public static ExpressionFingerprint Create(Expression expression, ParserContext parserContext) {\r
77             {\r
78                 BinaryExpression binaryExpression = expression as BinaryExpression;\r
79                 if (binaryExpression != null) {\r
80                     return BinaryExpressionFingerprint.Create(binaryExpression, parserContext);\r
81                 }\r
82             }\r
83 \r
84             {\r
85                 ConditionalExpression conditionalExpression = expression as ConditionalExpression;\r
86                 if (conditionalExpression != null) {\r
87                     return ConditionalExpressionFingerprint.Create(conditionalExpression, parserContext);\r
88                 }\r
89             }\r
90 \r
91             {\r
92                 ConstantExpression constantExpression = expression as ConstantExpression;\r
93                 if (constantExpression != null) {\r
94                     return ConstantExpressionFingerprint.Create(constantExpression, parserContext);\r
95                 }\r
96             }\r
97 \r
98             {\r
99                 MemberExpression memberExpression = expression as MemberExpression;\r
100                 if (memberExpression != null) {\r
101                     return MemberExpressionFingerprint.Create(memberExpression, parserContext);\r
102                 }\r
103             }\r
104 \r
105             {\r
106                 MethodCallExpression methodCallExpression = expression as MethodCallExpression;\r
107                 if (methodCallExpression != null) {\r
108                     return MethodCallExpressionFingerprint.Create(methodCallExpression, parserContext);\r
109                 }\r
110             }\r
111 \r
112             {\r
113                 ParameterExpression parameterExpression = expression as ParameterExpression;\r
114                 if (parameterExpression != null) {\r
115                     return ParameterExpressionFingerprint.Create(parameterExpression, parserContext);\r
116                 }\r
117             }\r
118 \r
119             {\r
120                 UnaryExpression unaryExpression = expression as UnaryExpression;\r
121                 if (unaryExpression != null) {\r
122                     return UnaryExpressionFingerprint.Create(unaryExpression, parserContext);\r
123                 }\r
124             }\r
125 \r
126             // unknown expression\r
127             return null;\r
128         }\r
129 \r
130         public static ReadOnlyCollection<ExpressionFingerprint> Create(IEnumerable<Expression> expressions, ParserContext parserContext) {\r
131             List<ExpressionFingerprint> fingerprints = new List<ExpressionFingerprint>();\r
132             foreach (Expression expression in expressions) {\r
133                 ExpressionFingerprint fingerprint = Create(expression, parserContext);\r
134                 if (fingerprint == null && expression != null) {\r
135                     // something couldn't be parsed properly\r
136                     return null;\r
137                 }\r
138                 else {\r
139                     fingerprints.Add(fingerprint);\r
140                 }\r
141             }\r
142             return new ReadOnlyCollection<ExpressionFingerprint>(fingerprints);\r
143         }\r
144 \r
145         public override int GetHashCode() {\r
146             HashCodeCombiner combiner = new HashCodeCombiner();\r
147             combiner.AddObject(GetType());\r
148             AddToHashCodeCombiner(combiner);\r
149             return combiner.CombinedHash;\r
150         }\r
151 \r
152         public override bool Equals(object obj) {\r
153             ExpressionFingerprint other = obj as ExpressionFingerprint;\r
154             if (other == null) {\r
155                 return false;\r
156             }\r
157 \r
158             return (this.NodeType == other.NodeType\r
159                 && this.Type == other.Type\r
160                 && this.GetType() == other.GetType());\r
161         }\r
162 \r
163         protected static Expression ToExpression(ExpressionFingerprint fingerprint, ParserContext parserContext) {\r
164             return (fingerprint != null) ? fingerprint.ToExpression(parserContext) : null;\r
165         }\r
166 \r
167         protected static IEnumerable<Expression> ToExpression(IEnumerable<ExpressionFingerprint> fingerprints, ParserContext parserContext) {\r
168             return from fingerprint in fingerprints select ToExpression(fingerprint, parserContext);\r
169         }\r
170 \r
171         public abstract Expression ToExpression(ParserContext parserContext);\r
172 \r
173     }\r
174 }\r