2009-06-12 Bill Holmes <billholmes54@gmail.com>
[mono.git] / mcs / class / System.Data.Linq / src / DbLinq / Data / Linq / Sugar / Implementation / SpecialExpressionTranslator.cs
1 #region MIT license\r
2 // \r
3 // MIT license\r
4 //\r
5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne\r
6 // \r
7 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
8 // of this software and associated documentation files (the "Software"), to deal\r
9 // in the Software without restriction, including without limitation the rights\r
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
11 // copies of the Software, and to permit persons to whom the Software is\r
12 // furnished to do so, subject to the following conditions:\r
13 // \r
14 // The above copyright notice and this permission notice shall be included in\r
15 // all copies or substantial portions of the Software.\r
16 // \r
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
23 // THE SOFTWARE.\r
24 // \r
25 #endregion\r
26 \r
27 using System;\r
28 using System.Collections.Generic;\r
29 using System.Linq;\r
30 using System.Linq.Expressions;\r
31 \r
32 #if MONO_STRICT\r
33 using System.Data.Linq.Sugar;\r
34 using System.Data.Linq.Sugar.ExpressionMutator;\r
35 using System.Data.Linq.Sugar.Expressions;\r
36 #else\r
37 using DbLinq.Data.Linq.Sugar;\r
38 using DbLinq.Data.Linq.Sugar.ExpressionMutator;\r
39 using DbLinq.Data.Linq.Sugar.Expressions;\r
40 #endif\r
41 \r
42 #if MONO_STRICT\r
43 namespace System.Data.Linq.Sugar.Implementation\r
44 #else\r
45 namespace DbLinq.Data.Linq.Sugar.Implementation\r
46 #endif\r
47 {\r
48     internal class SpecialExpressionTranslator : ISpecialExpressionTranslator\r
49     {\r
50         /// <summary>\r
51         /// Translate a hierarchy's SpecialExpressions to Expressions\r
52         /// </summary>\r
53         /// <param name="expression"></param>\r
54         /// <returns></returns>\r
55         public Expression Translate(Expression expression)\r
56         {\r
57             return expression.Recurse(Analyzer);\r
58         }\r
59 \r
60         protected virtual Expression Analyzer(Expression expression)\r
61         {\r
62             if (expression is SpecialExpression)\r
63                 return Translate((SpecialExpression)expression);\r
64             else if (expression is StartIndexOffsetExpression)\r
65                 return Translate(((StartIndexOffsetExpression)expression).InnerExpression);\r
66             return expression;\r
67         }\r
68 \r
69         /// <summary>\r
70         /// Translates a SpecialExpression to standard Expression equivalent\r
71         /// </summary>\r
72         /// <param name="specialExpression"></param>\r
73         /// <returns></returns>\r
74         protected virtual Expression Translate(SpecialExpression specialExpression)\r
75         {\r
76             var operands = specialExpression.Operands.ToList();\r
77             switch (specialExpression.SpecialNodeType)  // SETuse\r
78             {\r
79                 case SpecialExpressionType.IsNull:\r
80                     return TranslateIsNull(operands);\r
81                 case SpecialExpressionType.IsNotNull:\r
82                     return TranslateIsNotNull(operands);\r
83                 case SpecialExpressionType.Concat:\r
84                     return TranslateConcat(operands);\r
85                 //case SpecialExpressionType.Count:\r
86                 //    break;\r
87                 //case SpecialExpressionType.Like:\r
88                 //    break;\r
89                 //case SpecialExpressionType.Min:\r
90                 //    break;\r
91                 //case SpecialExpressionType.Max:\r
92                 //    break;\r
93                 //case SpecialExpressionType.Sum:\r
94                 //    break;\r
95                 //case SpecialExpressionType.Average:\r
96                 //    break;\r
97                 case SpecialExpressionType.StringLength:\r
98                     return TranslateStringLength(operands);\r
99                 case SpecialExpressionType.ToUpper:\r
100                     return GetStandardCallInvoke("ToUpper", operands);\r
101                 case SpecialExpressionType.ToLower:\r
102                     return GetStandardCallInvoke("ToLower", operands);\r
103                 //case SpecialExpressionType.In:\r
104                 //    break;\r
105 \r
106                 case SpecialExpressionType.StringInsert:\r
107                     return GetStandardCallInvoke("Insert", operands);\r
108                 case SpecialExpressionType.Substring:\r
109                 case SpecialExpressionType.Trim:\r
110                 case SpecialExpressionType.LTrim:\r
111                 case SpecialExpressionType.RTrim:\r
112                 case SpecialExpressionType.Replace:\r
113                 case SpecialExpressionType.Remove:\r
114                 case SpecialExpressionType.IndexOf:\r
115                 case SpecialExpressionType.Year:\r
116                 case SpecialExpressionType.Month:\r
117                 case SpecialExpressionType.Day:\r
118                 case SpecialExpressionType.Hour:\r
119                 case SpecialExpressionType.Minute:\r
120                 case SpecialExpressionType.Millisecond:\r
121                     return GetStandardCallInvoke(specialExpression.SpecialNodeType.ToString(), operands);\r
122                 case SpecialExpressionType.Now:\r
123                     return GetDateTimeNowCall(operands);\r
124                 case SpecialExpressionType.DateDiffInMilliseconds:\r
125                     return GetCallDateDiffInMilliseconds(operands);\r
126                 default:\r
127                     throw Error.BadArgument("S0078: Implement translator for {0}", specialExpression.SpecialNodeType);\r
128 \r
129             }\r
130         }\r
131 \r
132         private Expression GetCallDateDiffInMilliseconds(List<Expression> operands)\r
133         {\r
134             return Expression.MakeMemberAccess(Expression.Subtract(operands.First(), operands.ElementAt(1)),\r
135                                                 typeof(TimeSpan).GetProperty("TotalMilliseconds"));\r
136         }\r
137 \r
138         private Expression GetDateTimeNowCall(List<Expression> operands)\r
139         {\r
140             return Expression.Call(typeof(DateTime).GetProperty("Now").GetGetMethod());\r
141         }\r
142 \r
143         private Expression TranslateStringLength(List<Expression> operands)\r
144         {\r
145             return Expression.MakeMemberAccess(operands[0], typeof(string).GetProperty("Length"));\r
146         }\r
147 \r
148         protected virtual Expression GetStandardCallInvoke(string methodName, List<Expression> operands)\r
149         {\r
150             var parametersExpressions = operands.Skip(1);\r
151             return Expression.Call(operands[0],\r
152                                    operands[0].Type.GetMethod(methodName, parametersExpressions.Select(op => op.Type).ToArray()),\r
153                                    parametersExpressions);\r
154         }\r
155 \r
156         //protected virtual Expression TranslateRemove(List<Expression> operands)\r
157         //{\r
158         //    if (operands.Count > 2)\r
159         //    {\r
160         //        return Expression.Call(operands[0], \r
161         //                            typeof(string).GetMethod("Remove", new[] { typeof(int), typeof(int) }), \r
162         //                            operands[1], operands[2]);\r
163         //    }\r
164         //    return Expression.Call(operands[0], \r
165         //                            typeof(string).GetMethod("Remove", new[] { typeof(int) }),\r
166         //                            operands[1]);\r
167         //}\r
168 \r
169         //protected virtual Expression TranslateStringIndexOf(List<Expression> operands)\r
170         //{\r
171         //    if (operands.Count == 2 && operands[1].Type == typeof(string))\r
172         //    {\r
173         //         return Expression.Call(operands[0], \r
174         //                            typeof(string).GetMethod("IndexOf", new[] { typeof(string)}), \r
175         //                            operands[1]);\r
176         //    }\r
177         //    throw new NotSupportedException();\r
178         //}\r
179 \r
180         //protected virtual Expression TranslateReplace(List<Expression> operands)\r
181         //{\r
182         //    if (operands.ElementAt(1).Type == typeof(string))\r
183         //    {\r
184         //        return Expression.Call(operands[0],\r
185         //                           typeof(string).GetMethod("Replace", new[] { typeof(string), typeof(string) }),\r
186         //                           operands[1], operands[2]);\r
187         //    }\r
188         //    return Expression.Call(operands[0],\r
189         //                        typeof(string).GetMethod("Replace", new[] { typeof(char), typeof(char) }),\r
190         //                        operands[1], operands[2]);\r
191         //}\r
192         //protected virtual Expression TranslateInsertString(List<Expression> operands)\r
193         //{\r
194         //    return Expression.Call(operands.First(), typeof(string).GetMethod("Insert"), operands[1], operands[2]);\r
195         //}\r
196 \r
197         //protected virtual Expression TranslateTrim(List<Expression> operands)\r
198         //{\r
199         //    return Expression.Call(operands.First(), typeof(string).GetMethod("Trim", new Type[] { }));\r
200         //}\r
201         //protected virtual Expression TranslateSubString(List<Expression> operands)\r
202         //{\r
203         //    if (operands.Count > 2)\r
204         //    {\r
205         //        return Expression.Call(operands[0],\r
206         //                               typeof(string).GetMethod("Substring", new[] { operands[1].Type, operands[2].Type }),\r
207         //                               operands[1], operands[2]);\r
208         //    }\r
209 \r
210         //    return Expression.Call(operands[0],\r
211         //                           typeof(string).GetMethod("Substring", new[] { operands[1].Type }),\r
212         //                           operands[1]);\r
213         //}\r
214 \r
215         //protected virtual Expression TranslateToLower(List<Expression> operands)\r
216         //{\r
217         //    return Expression.Call(operands[0], typeof(string).GetMethod("ToLower", new Type[0]));\r
218         //}\r
219 \r
220         //protected virtual Expression TranslateToUpper(List<Expression> operands)\r
221         //{\r
222         //    return Expression.Call(operands[0], typeof(string).GetMethod("ToUpper", new Type[0]));\r
223         //}\r
224 \r
225         protected virtual Expression TranslateConcat(List<Expression> operands)\r
226         {\r
227             return Expression.Add(operands[0], operands[1]);\r
228         }\r
229 \r
230         protected virtual Expression TranslateIsNotNull(List<Expression> operands)\r
231         {\r
232             return Expression.NotEqual(operands[0], Expression.Constant(null));\r
233         }\r
234 \r
235         protected virtual Expression TranslateIsNull(List<Expression> operands)\r
236         {\r
237             return Expression.Equal(operands[0], Expression.Constant(null));\r
238         }\r
239     }\r
240 }