SHARE
TWEET

Untitled

a guest Apr 4th, 2015 209 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="ExpressionWriter.cs" company="Reimers.dk">
  3. //   Copyright © Reimers.dk 2012
  4. //   This source is subject to the Microsoft Public License (Ms-PL).
  5. //   Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  6. //   All other rights reserved.
  7. // </copyright>
  8. // <summary>
  9. //   Defines the ExpressionWriter type.
  10. // </summary>
  11. // --------------------------------------------------------------------------------------------------------------------
  12.  
  13. namespace Linq2Rest.Provider
  14. {
  15.     using System;
  16.     using System.Collections.Generic;
  17.     ////using System.Diagnostics.Contracts;
  18.     using System.Linq;
  19.     using System.Linq.Expressions;
  20.     using System.Reflection;
  21.     using Linq2Rest.Provider.Writers;
  22.  
  23.     public static class StringExtensions
  24.     {
  25.         public static bool IsNullOrWhiteSpace(string value)
  26.         {
  27.             if (value == null) return true;
  28.             return string.IsNullOrEmpty(value.Trim());
  29.         }
  30.     }
  31.  
  32.     internal class ExpressionWriter : IExpressionWriter
  33.     {
  34.         private static readonly ExpressionType[] CompositeExpressionTypes = new[] { ExpressionType.Or, ExpressionType.OrElse, ExpressionType.And, ExpressionType.AndAlso };
  35.         private readonly IMethodCallWriter[] _methodCallWriters = new IMethodCallWriter[]
  36.                                                                                                                                 {
  37.                                                                                                                                         new EqualsMethodWriter(),
  38.                                                                                                                                         new StringReplaceMethodWriter(),
  39.                                                                                                                                         new StringTrimMethodWriter(),
  40.                                                                                                                                         new StringToLowerMethodWriter(),
  41.                                                                                                                                         new StringToUpperMethodWriter(),
  42.                                                                                                                                         new StringSubstringMethodWriter(),
  43.                                                                                                                                         new StringContainsMethodWriter(),
  44.                                                                                                                                         new StringIndexOfMethodWriter(),
  45.                                                                                                                                         new StringEndsWithMethodWriter(),
  46.                                                                                                                                         new StringStartsWithMethodWriter(),
  47.                                                                                                                                         new MathRoundMethodWriter(),
  48.                                                                                                                                         new MathFloorMethodWriter(),
  49.                                                                                                                                         new MathCeilingMethodWriter(),
  50.                                                                                                                                         new EmptyAnyMethodWriter(),
  51.                                                                                                                                         new AnyAllMethodWriter(),
  52.                                                                                                                                         new DefaultMethodWriter()
  53.                                                                                                                                 };
  54.  
  55.         public string Write(Expression expression)
  56.         {
  57.             return expression == null ? null : Write(expression, expression.Type, GetRootParameterName(expression));
  58.         }
  59.  
  60.         private static Type GetUnconvertedType(Expression expression)
  61.         {
  62.             ////Contract.Requires(expression != null);
  63.  
  64.             switch (expression.NodeType)
  65.             {
  66.                 case ExpressionType.Convert:
  67.                     var unaryExpression = expression as UnaryExpression;
  68.  
  69.                     //Contract.Assume(unaryExpression != null, "Matches node type.");
  70.  
  71.                     return unaryExpression.Operand.Type;
  72.                 default:
  73.                     return expression.Type;
  74.             }
  75.         }
  76.  
  77.         private static string GetMemberCall(MemberExpression memberExpression)
  78.         {
  79.             //Contract.Requires(memberExpression != null);
  80.             //Contract.Ensures(Contract.Result<string>() != null);
  81.  
  82.             var declaringType = memberExpression.Member.DeclaringType;
  83.             var name = memberExpression.Member.Name;
  84.  
  85.             if (declaringType == typeof(string) && string.Equals(name, "Length"))
  86.             {
  87.                 return name.ToLowerInvariant();
  88.             }
  89.  
  90.             if (declaringType == typeof(DateTime))
  91.             {
  92.                 switch (name)
  93.                 {
  94.                     case "Hour":
  95.                     case "Minute":
  96.                     case "Second":
  97.                     case "Day":
  98.                     case "Month":
  99.                     case "Year":
  100.                         return name.ToLowerInvariant();
  101.                 }
  102.             }
  103.  
  104.             return string.Empty;
  105.         }
  106.  
  107.         private static Expression CollapseCapturedOuterVariables(MemberExpression input)
  108.         {
  109.             if (input == null || input.NodeType != ExpressionType.MemberAccess)
  110.             {
  111.                 return input;
  112.             }
  113.  
  114.             switch (input.Expression.NodeType)
  115.             {
  116.                 case ExpressionType.New:
  117.                 case ExpressionType.MemberAccess:
  118.                     var value = GetValue(input);
  119.                     return Expression.Constant(value);
  120.                 case ExpressionType.Constant:
  121.                     var obj = ((ConstantExpression)input.Expression).Value;
  122.                     if (obj == null)
  123.                     {
  124.                         return input;
  125.                     }
  126.  
  127.                     var fieldInfo = input.Member as FieldInfo;
  128.                     if (fieldInfo != null)
  129.                     {
  130.                         var result = fieldInfo.GetValue(obj);
  131.                         return result is Expression ? (Expression)result : Expression.Constant(result);
  132.                     }
  133.  
  134.                     var propertyInfo = input.Member as PropertyInfo;
  135.                     if (propertyInfo != null)
  136.                     {
  137.                         var result = propertyInfo.GetValue(obj, null);
  138.                         return result is Expression ? (Expression)result : Expression.Constant(result);
  139.                     }
  140.  
  141.                     break;
  142.                 case ExpressionType.TypeAs:
  143.                 case ExpressionType.Convert:
  144.                 case ExpressionType.ConvertChecked:
  145.                     return Expression.Constant(GetValue(input));
  146.             }
  147.  
  148.             return input;
  149.         }
  150.  
  151.         private static object GetValue(Expression input)
  152.         {
  153.             //Contract.Requires(input != null);
  154.  
  155.             var objectMember = Expression.Convert(input, typeof(object));
  156.             var getterLambda = Expression.Lambda<Func<object>>(objectMember).Compile();
  157.  
  158.             return getterLambda();
  159.         }
  160.  
  161.         private static bool IsMemberOfParameter(MemberExpression input)
  162.         {
  163.             if (input == null || input.Expression == null)
  164.             {
  165.                 return false;
  166.             }
  167.  
  168.             var nodeType = input.Expression.NodeType;
  169.             var tempExpression = input.Expression as MemberExpression;
  170.             while (nodeType == ExpressionType.MemberAccess)
  171.             {
  172.                 if (tempExpression == null || tempExpression.Expression == null)
  173.                 {
  174.                     return false;
  175.                 }
  176.  
  177.                 nodeType = tempExpression.Expression.NodeType;
  178.                 tempExpression = tempExpression.Expression as MemberExpression;
  179.             }
  180.  
  181.             return nodeType == ExpressionType.Parameter;
  182.         }
  183.  
  184.         private static string GetOperation(Expression expression)
  185.         {
  186.             //Contract.Requires(expression != null);
  187.  
  188.             switch (expression.NodeType)
  189.             {
  190.                 case ExpressionType.Add:
  191.                     return "add";
  192.                 case ExpressionType.AddChecked:
  193.                     break;
  194.                 case ExpressionType.And:
  195.                 case ExpressionType.AndAlso:
  196.                     return "and";
  197.                 case ExpressionType.Divide:
  198.                     return "div";
  199.                 case ExpressionType.Equal:
  200.                     return "eq";
  201.                 case ExpressionType.GreaterThan:
  202.                     return "gt";
  203.                 case ExpressionType.GreaterThanOrEqual:
  204.                     return "ge";
  205.                 case ExpressionType.LessThan:
  206.                     return "lt";
  207.                 case ExpressionType.LessThanOrEqual:
  208.                     return "le";
  209.                 case ExpressionType.Modulo:
  210.                     return "mod";
  211.                 case ExpressionType.Multiply:
  212.                     return "mul";
  213.                 case ExpressionType.Not:
  214.                     return "not";
  215.                 case ExpressionType.NotEqual:
  216.                     return "ne";
  217.                 case ExpressionType.Or:
  218.                 case ExpressionType.OrElse:
  219.                     return "or";
  220.                 case ExpressionType.Subtract:
  221.                     return "sub";
  222.             }
  223.  
  224.             return string.Empty;
  225.         }
  226.  
  227.         private static ParameterExpression GetRootParameterName(Expression expression)
  228.         {
  229.             if (expression is UnaryExpression)
  230.             {
  231.                 expression = ((UnaryExpression)expression).Operand;
  232.             }
  233.  
  234.             if (expression is LambdaExpression && ((LambdaExpression)expression).Parameters.Any())
  235.             {
  236.                 return ((LambdaExpression)expression).Parameters.First();
  237.             }
  238.  
  239.             return null;
  240.         }
  241.  
  242.         private string Write(Expression expression, ParameterExpression rootParameterName)
  243.         {
  244.             return expression == null ? null : Write(expression, expression.Type, rootParameterName);
  245.         }
  246.  
  247.         private string Write(Expression expression, Type type, ParameterExpression rootParameter)
  248.         {
  249.             //Contract.Requires(expression != null);
  250.             //Contract.Requires(type != null);
  251.  
  252.             switch (expression.NodeType)
  253.             {
  254.                 case ExpressionType.Parameter:
  255.                     var parameterExpression = expression as ParameterExpression;
  256.  
  257.                     //Contract.Assume(parameterExpression != null);
  258.  
  259.                     return parameterExpression.Name;
  260.                 case ExpressionType.Constant:
  261.                     {
  262.                         var value = GetValue(Expression.Convert(expression, type));
  263.                         return ParameterValueWriter.Write(value);
  264.                     }
  265.  
  266.                 case ExpressionType.Add:
  267.                 case ExpressionType.And:
  268.                 case ExpressionType.AndAlso:
  269.                 case ExpressionType.Divide:
  270.                 case ExpressionType.Equal:
  271.                 case ExpressionType.GreaterThan:
  272.                 case ExpressionType.GreaterThanOrEqual:
  273.                 case ExpressionType.LessThan:
  274.                 case ExpressionType.LessThanOrEqual:
  275.                 case ExpressionType.Modulo:
  276.                 case ExpressionType.Multiply:
  277.                 case ExpressionType.NotEqual:
  278.                 case ExpressionType.Or:
  279.                 case ExpressionType.OrElse:
  280.                 case ExpressionType.Subtract:
  281.                     return WriteBinaryExpression(expression, rootParameter);
  282.                 case ExpressionType.Negate:
  283.                     return WriteNegate(expression, rootParameter);
  284.                 case ExpressionType.Not:
  285. #if !SILVERLIGHT && false
  286.                 case ExpressionType.IsFalse:
  287. #endif
  288.                     return WriteFalse(expression, rootParameter);
  289. #if !SILVERLIGHT && false
  290.                 case ExpressionType.IsTrue:
  291.                     return WriteTrue(expression, rootParameter);
  292. #endif
  293.                 case ExpressionType.Convert:
  294.                 case ExpressionType.Quote:
  295.                     return WriteConversion(expression, rootParameter);
  296.                 case ExpressionType.MemberAccess:
  297.                     return WriteMemberAccess(expression, rootParameter);
  298.                 case ExpressionType.Call:
  299.                     return WriteCall(expression, rootParameter);
  300.                 case ExpressionType.New:
  301.                 case ExpressionType.ArrayIndex:
  302.                 case ExpressionType.ArrayLength:
  303.                 case ExpressionType.Conditional:
  304.                 case ExpressionType.Coalesce:
  305.                     var newValue = GetValue(expression);
  306.                     return ParameterValueWriter.Write(newValue);
  307.                 case ExpressionType.Lambda:
  308.                     return WriteLambda(expression, rootParameter);
  309.                 default:
  310.                     throw new InvalidOperationException("Expression is not recognized or supported");
  311.             }
  312.         }
  313.  
  314.         private string WriteLambda(Expression expression, ParameterExpression rootParameter)
  315.         {
  316.             var lambdaExpression = expression as LambdaExpression;
  317.  
  318.             //Contract.Assume(lambdaExpression != null);
  319.  
  320.             var body = lambdaExpression.Body;
  321.             return Write(body, rootParameter);
  322.         }
  323.  
  324.         private string WriteFalse(Expression expression, ParameterExpression rootParameterName)
  325.         {
  326.             var unaryExpression = expression as UnaryExpression;
  327.  
  328.             //Contract.Assume(unaryExpression != null);
  329.  
  330.             var operand = unaryExpression.Operand;
  331.  
  332.             return string.Format("not({0})", Write(operand, rootParameterName));
  333.         }
  334.  
  335.         private string WriteTrue(Expression expression, ParameterExpression rootParameterName)
  336.         {
  337.             var unaryExpression = expression as UnaryExpression;
  338.  
  339.             //Contract.Assume(unaryExpression != null);
  340.  
  341.             var operand = unaryExpression.Operand;
  342.  
  343.             return Write(operand, rootParameterName);
  344.         }
  345.  
  346.         private string WriteConversion(Expression expression, ParameterExpression rootParameterName)
  347.         {
  348.             var unaryExpression = expression as UnaryExpression;
  349.  
  350.             //Contract.Assume(unaryExpression != null);
  351.  
  352.             var operand = unaryExpression.Operand;
  353.             return Write(operand, rootParameterName);
  354.         }
  355.  
  356.         private string WriteCall(Expression expression, ParameterExpression rootParameterName)
  357.         {
  358.             var methodCallExpression = expression as MethodCallExpression;
  359.  
  360.             //Contract.Assume(methodCallExpression != null);
  361.  
  362.             return GetMethodCall(methodCallExpression, rootParameterName);
  363.         }
  364.  
  365.         private string WriteMemberAccess(Expression expression, ParameterExpression rootParameterName)
  366.         {
  367.             var memberExpression = expression as MemberExpression;
  368.  
  369.             //Contract.Assume(memberExpression != null);
  370.  
  371.             if (memberExpression.Expression == null)
  372.             {
  373.                 var memberValue = GetValue(memberExpression);
  374.                 return ParameterValueWriter.Write(memberValue);
  375.             }
  376.  
  377.             var pathPrefixes = new List<string>();
  378.  
  379.             var currentMemberExpression = memberExpression;
  380.             while (currentMemberExpression != null)
  381.             {
  382.                 pathPrefixes.Add(currentMemberExpression.Member.Name);
  383.                 if (currentMemberExpression.Expression is ParameterExpression
  384.                     && rootParameterName != null
  385.                     && ((ParameterExpression)currentMemberExpression.Expression).Name != rootParameterName.Name)
  386.                 {
  387.                     pathPrefixes.Add(((ParameterExpression)currentMemberExpression.Expression).Name);
  388.                 }
  389.  
  390.                 currentMemberExpression = currentMemberExpression.Expression as MemberExpression;
  391.             }
  392.  
  393.             pathPrefixes.Reverse();
  394.             var prefix = string.Join("/", pathPrefixes.ToArray());
  395.  
  396.             if (!IsMemberOfParameter(memberExpression))
  397.             {
  398.                 var collapsedExpression = CollapseCapturedOuterVariables(memberExpression);
  399.                 if (!(collapsedExpression is MemberExpression))
  400.                 {
  401.                     //Contract.Assume(collapsedExpression != null);
  402.  
  403.                     return Write(collapsedExpression, rootParameterName);
  404.                 }
  405.  
  406.                 memberExpression = (MemberExpression)collapsedExpression;
  407.             }
  408.  
  409.             var memberCall = GetMemberCall(memberExpression);
  410.  
  411.             var innerExpression = memberExpression.Expression;
  412.  
  413.             //Contract.Assume(innerExpression != null);
  414.  
  415.             return StringExtensions.IsNullOrWhiteSpace(memberCall)
  416.                        ? prefix
  417.                        : string.Format("{0}({1})", memberCall, Write(innerExpression, rootParameterName));
  418.         }
  419.  
  420.         private string WriteNegate(Expression expression, ParameterExpression rootParameterName)
  421.         {
  422.             var unaryExpression = expression as UnaryExpression;
  423.  
  424.             //Contract.Assume(unaryExpression != null);
  425.  
  426.             var operand = unaryExpression.Operand;
  427.  
  428.             return string.Format("-{0}", Write(operand, rootParameterName));
  429.         }
  430.  
  431.         private string WriteBinaryExpression(Expression expression, ParameterExpression rootParameterName)
  432.         {
  433.             var binaryExpression = expression as BinaryExpression;
  434.  
  435.             //Contract.Assume(binaryExpression != null);
  436.  
  437.             var operation = GetOperation(binaryExpression);
  438.  
  439.             if (binaryExpression.Left.NodeType == ExpressionType.Call)
  440.             {
  441.                 var compareResult = ResolveCompareToOperation(
  442.                     rootParameterName,
  443.                     (MethodCallExpression)binaryExpression.Left,
  444.                     operation,
  445.                     binaryExpression.Right as ConstantExpression);
  446.                 if (compareResult != null)
  447.                 {
  448.                     return compareResult;
  449.                 }
  450.             }
  451.  
  452.             if (binaryExpression.Right.NodeType == ExpressionType.Call)
  453.             {
  454.                 var compareResult = ResolveCompareToOperation(
  455.                     rootParameterName,
  456.                     (MethodCallExpression)binaryExpression.Right,
  457.                     operation,
  458.                     binaryExpression.Left as ConstantExpression);
  459.                 if (compareResult != null)
  460.                 {
  461.                     return compareResult;
  462.                 }
  463.             }
  464.  
  465.             var isLeftComposite = CompositeExpressionTypes.Any(x => x == binaryExpression.Left.NodeType);
  466.             var isRightComposite = CompositeExpressionTypes.Any(x => x == binaryExpression.Right.NodeType);
  467.  
  468.             var leftType = GetUnconvertedType(binaryExpression.Left);
  469.             var leftString = Write(binaryExpression.Left, rootParameterName);
  470.             var rightString = Write(binaryExpression.Right, leftType, rootParameterName);
  471.  
  472.             return string.Format(
  473.                 "{0} {1} {2}",
  474.                 string.Format(isLeftComposite ? "({0})" : "{0}", leftString),
  475.                 operation,
  476.                 string.Format(isRightComposite ? "({0})" : "{0}", rightString));
  477.         }
  478.  
  479.         private string ResolveCompareToOperation(
  480.             ParameterExpression rootParameterName,
  481.             MethodCallExpression methodCallExpression,
  482.             string operation,
  483.             ConstantExpression comparisonExpression)
  484.         {
  485.             if (methodCallExpression != null
  486.                 && methodCallExpression.Method.Name == "CompareTo"
  487.                 && methodCallExpression.Method.ReturnType == typeof(int)
  488.                 && comparisonExpression != null
  489.                 && Equals(comparisonExpression.Value, 0))
  490.             {
  491.                 return string.Format(
  492.                     "{0} {1} {2}",
  493.                     Write(methodCallExpression.Object, rootParameterName),
  494.                     operation,
  495.                     Write(methodCallExpression.Arguments[0], rootParameterName));
  496.             }
  497.  
  498.             return null;
  499.         }
  500.  
  501.         private string GetMethodCall(MethodCallExpression expression, ParameterExpression rootParameterName)
  502.         {
  503.             //Contract.Requires(expression != null);
  504.  
  505.             var methodCallWriter = _methodCallWriters.FirstOrDefault(w => w.CanHandle(expression));
  506.             if (methodCallWriter == null)
  507.             {
  508.                 throw new NotSupportedException(expression + " is not supported");
  509.             }
  510.  
  511.             return methodCallWriter.Handle(expression, e => Write(e, rootParameterName));
  512.         }
  513.     }
  514. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top