5 // Copyright (c) 2007-2008 Jiri Moudry, Pascal Craponne
\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
14 // The above copyright notice and this permission notice shall be included in
\r
15 // all copies or substantial portions of the Software.
\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
28 using System.Collections.Generic;
\r
30 using System.Linq.Expressions;
\r
31 using System.Reflection;
\r
34 using System.Data.Linq.Sugar;
\r
35 using System.Data.Linq.Sugar.ExpressionMutator;
\r
37 using DbLinq.Data.Linq.Sugar;
\r
38 using DbLinq.Data.Linq.Sugar.ExpressionMutator;
\r
42 namespace System.Data.Linq.Sugar.Implementation
\r
44 namespace DbLinq.Data.Linq.Sugar.Implementation
\r
48 /// Analyzes language patterns and replace them with standard expressions
\r
50 internal class ExpressionLanguageParser : IExpressionLanguageParser
\r
52 public virtual Expression Parse(Expression expression, BuilderContext builderContext)
\r
54 return expression.Recurse(e => Analyze(e, builderContext));
\r
57 protected delegate Expression Analyzer(Expression expression);
\r
59 protected IEnumerable<Analyzer> Analyzers;
\r
60 private readonly object analyzersLock = new object();
\r
62 protected virtual IEnumerable<Analyzer> GetAnalyzers()
\r
64 lock (analyzersLock)
\r
66 if (Analyzers == null)
\r
68 // man, this is the kind of line I'm proud of :)
\r
69 Analyzers = from method in GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
\r
70 let m = (Analyzer)Delegate.CreateDelegate(typeof(Analyzer), this, method, false)
\r
73 Analyzers = Analyzers.ToList(); // result is faster from here
\r
79 protected virtual Expression Analyze(Expression expression, BuilderContext builderContext)
\r
81 foreach (var analyze in GetAnalyzers())
\r
83 var e = analyze(expression);
\r
91 /// Tests for Convert.ToBoolean()
\r
93 /// <param name="expression"></param>
\r
94 /// <returns></returns>
\r
95 protected virtual Expression AnalyzeConvertToBoolean(Expression expression)
\r
97 var methodCallExpression = expression as MethodCallExpression;
\r
98 if (methodCallExpression != null)
\r
100 if (methodCallExpression.Method.DeclaringType.Name == "Convert")
\r
102 if (methodCallExpression.Method.Name == "ToBoolean")
\r
103 return Expression.Convert(methodCallExpression.Arguments[0], methodCallExpression.Type);
\r
110 /// Used to determine if the Expression is a VB CompareString
\r
111 /// Returns an equivalent Expression if true
\r
113 /// <param name="expression"></param>
\r
114 /// <returns></returns>
\r
115 protected virtual Expression AnalyzeCompareString(Expression expression)
\r
118 var testedExpression = GetComparedToZero(expression, out equals);
\r
119 if (testedExpression != null)
\r
121 var methodExpression = testedExpression as MethodCallExpression;
\r
122 if (methodExpression != null
\r
123 && methodExpression.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators"
\r
124 && methodExpression.Method.Name == "CompareString")
\r
126 return Expression.Equal(methodExpression.Arguments[0], methodExpression.Arguments[1]);
\r
132 protected virtual Expression AnalyzeLikeString(Expression expression)
\r
134 var methodExpression = expression as MethodCallExpression;
\r
135 if (methodExpression != null
\r
136 && methodExpression.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.LikeOperator"
\r
137 && methodExpression.Method.Name == "LikeString")
\r
139 var lambda = (Expression<Func<string, string, bool>>)((a, b) => a.StartsWith(b));
\r
140 return Expression.Invoke(lambda, methodExpression.Arguments[0], methodExpression.Arguments[1]);
\r
146 /// Determines if an expression is a comparison to 0
\r
148 /// <param name="expression"></param>
\r
149 /// <param name="equals">True if ==, False if !=</param>
\r
150 /// <returns>The compared Expression or null</returns>
\r
151 protected static Expression GetComparedToZero(Expression expression, out bool equals)
\r
153 equals = expression.NodeType == ExpressionType.Equal;
\r
154 if (equals || expression.NodeType == ExpressionType.NotEqual)
\r
156 var binaryExpression = (BinaryExpression)expression;
\r
157 if (IsZero(binaryExpression.Right))
\r
158 return binaryExpression.Left;
\r
159 if (IsZero(binaryExpression.Left))
\r
160 return binaryExpression.Right;
\r
166 /// Determines if an expression is constant value 0
\r
168 /// <param name="expression"></param>
\r
169 /// <returns></returns>
\r
170 protected static bool IsZero(Expression expression)
\r
172 if (expression.NodeType == ExpressionType.Constant)
\r
174 var unaryExpression = (ConstantExpression)expression;
\r
175 return (unaryExpression.Value as int? ?? 0) == 0; // you too, have fun with C# operators
\r