RequestQueryParser.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWeb / Server / System / Data / Services / Parsing / RequestQueryParser.cs / 1 / RequestQueryParser.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a type to parse expressions in request queries.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Parsing
{
    #region Namespaces. 

    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq; 
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Data.Services.Parsing;
    using System.Data.Services.Providers; 
#if ASTORIA_OPEN_OBJECT
    using System.Data.Services.OpenTypes; 
#endif 

    #endregion Namespaces. 

    /// 
    /// This class provides static methods to parse query options and compose
    /// them on an existing query. 
    /// 
    internal static class RequestQueryParser 
    { 
        #region Fields.
 
        /// Constant for "null" literal.
        internal static readonly ConstantExpression NullLiteral = Expression.Constant(null);

        #endregion Fields. 

        #region Internal methods. 
 
        /// Gets a type for  that allows null values.
        /// Type to base resulting type on. 
        /// 
        ///  if it's a reference or Nullable<> type;
        /// Nullable<> otherwise.
        ///  
        internal static Type GetTypeAllowingNull(Type type)
        { 
            Debug.Assert(type != null, "type != null"); 
            return TypeAllowsNull(type) ? type : typeof(Nullable<>).MakeGenericType(type);
        } 

        /// Checks whether the specified type is a generic nullable type.
        /// Type to check.
        /// true if  is nullable; false otherwise. 
        internal static bool IsNullableType(Type type)
        { 
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); 
        }
 
        /// Checks whether  is a null constant.
        /// Expression to check.
        /// true if  is a null constant; false otherwise.
        internal static bool IsNullConstant(Expression expression) 
        {
            Debug.Assert(expression != null, "expression != null"); 
            return 
                expression == NullLiteral ||
                (expression.NodeType == ExpressionType.Constant && ((ConstantExpression)expression).Value == null); 
        }

        /// Checks whether the specified  can be assigned null.
        /// Type to check. 
        /// true if type is a reference type or a Nullable type; false otherwise.
        internal static bool TypeAllowsNull(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
            return !type.IsValueType || IsNullableType(type); 
        }

        /// Sorts a query like a SQL ORDER BY clause does.
        /// Service with data and configuration. 
        /// Original source for query.
        /// Ordering definition to compose. 
        /// The composed query. 
        internal static IQueryable OrderBy(IDataService service, IQueryable source, string ordering)
        { 
            Debug.Assert(service != null, "service != null");
            Debug.Assert(source != null, "source != null");
            Debug.Assert(ordering != null, "ordering != null");
 
            ParameterExpression parameterForIt = Expression.Parameter(source.ElementType, "it");
            ExpressionParser parser = new ExpressionParser(service, parameterForIt, ordering); 
            IEnumerable orderings = parser.ParseOrdering(); 
            Expression queryExpr = source.Expression;
            string methodAsc = "OrderBy"; 
            string methodDesc = "OrderByDescending";
            foreach (DynamicOrdering o in orderings)
            {
                Type selectorType = o.Selector.Type; 
                if (!service.Provider.GetTypeIsOrdered(selectorType))
                { 
                    string resourceTypeName = WebUtil.GetTypeName(service.Provider, o.Selector.Type); 
                    throw DataServiceException.CreateBadRequestError(Strings.RequestQueryParser_OrderByDoesNotSupportType(resourceTypeName));
                } 

                queryExpr = Expression.Call(
                    typeof(Queryable),
                    o.Ascending ? methodAsc : methodDesc, 
                    new Type[] { source.ElementType, selectorType },
                    queryExpr, 
                    Expression.Quote(Expression.Lambda(o.Selector, parameterForIt))); 
                methodAsc = "ThenBy";
                methodDesc = "ThenByDescending"; 
            }

            return source.Provider.CreateQuery(queryExpr);
        } 

        /// Filters a query like a SQL WHERE clause does. 
        /// Service with data and configuration. 
        /// Original source for query.
        /// Predicate to compose. 
        /// The composed query.
        internal static IQueryable Where(IDataService service, IQueryable source, string predicate)
        {
            Debug.Assert(service != null, "service != null"); 
            Debug.Assert(service != null, "source != null");
            Debug.Assert(predicate != null, "predicate != null"); 
 
            LambdaExpression lambda = ParseLambdaForWhere(service, source.ElementType, predicate);
            ////Trace.WriteLine("predicate=" + predicate + "; lambda=" + lambda.ToString()); 
            return source.Provider.CreateQuery(
                Expression.Call(typeof(Queryable), "Where", new Type[] { source.ElementType }, source.Expression, Expression.Quote(lambda)));
        }
 
        #endregion Internal methods.
 
        #region Private methods. 

        /// Parses a lambda expression. 
        /// Service with data and configuration.
        /// Type for "it" contextual variable.
        /// Expression to parse.
        /// The parsed expression. 
        private static LambdaExpression ParseLambdaForWhere(IDataService service, Type typeForIt, string expression)
        { 
            Debug.Assert(service != null, "service != null"); 
            Debug.Assert(typeForIt != null, "typeForIt != null");
            Debug.Assert(expression != null, "expression != null"); 
            ParameterExpression parameterForIt = Expression.Parameter(typeForIt, "it");
            ExpressionParser parser = new ExpressionParser(service, parameterForIt, expression);
            return Expression.Lambda(parser.ParseWhere(), parameterForIt);
        } 

        #endregion Private methods. 
 
        /// Use this class to define ordering for resources.
        private class DynamicOrdering 
        {
            #region Private fields.

            /// Whether the order is ascending. 
            private readonly bool ascending;
 
            /// Selector expression in ordering. 
            private readonly Expression selector;
 
            #endregion Private fields.

            /// Initializes a new  instance.
            /// Selector expression in ordering. 
            /// Whether the order is ascending.
            internal DynamicOrdering(Expression selector, bool ascending) 
            { 
                this.selector = selector;
                this.ascending = ascending; 
            }

            #region Properties.
 
            /// Whether the order is ascending.
            internal bool Ascending 
            { 
                get { return this.ascending; }
            } 

            /// Selector expression in ordering.
            internal Expression Selector
            { 
                get { return this.selector; }
            } 
 
            #endregion Properties.
        } 

        /// Use this class to parse an expression in the Astoria URI format.
        [DebuggerDisplay("ExpressionParser ({lexer.text})")]
        private class ExpressionParser 
        {
            #region Fields. 
 
            /// Maximum recursion limit on deserializer.
            private const int RecursionLimit = 100; 

            /// A type that is not numeric.
            private const int NumericTypeNotNumeric = 0;
 
            /// A type that is a char, single, double or decimal.
            private const int NumericTypeNotIntegral = 1; 
 
            /// A type that is a signed integral.
            private const int NumericTypeSignedIntegral = 2; 

            /// A type that is an unsigned integral.
            private const int NumericTypeUnsignedIntegral = 3;
 
            /// Empty Expressions array.
            private static readonly Expression[] emptyExpressions = new Expression[0]; 
 
            /// Constant for "true" literal.
            private static readonly ConstantExpression trueLiteral = Expression.Constant(true); 

            /// Constant for "false" literal.
            private static readonly ConstantExpression falseLiteral = Expression.Constant(false);
 
            /// Dictionary of system functions.
            private static readonly Dictionary functions = FunctionDescription.CreateFunctions(); 
 
            /// Provider of data and metadata.
            private readonly IDataServiceProvider provider; 

            /// Service with data and configuration.
            private readonly IDataService service;
 
            /// Literals.
            private Dictionary literals; 
 
            /// "it" contextual parameter.
            private ParameterExpression it; 

            /// Expression lexer.
            private ExpressionLexer lexer;
 
            /// Whether the expression tree should propagate nulls explicitly.
            private bool nullPropagationRequired; 
 
            /// Depth of recursion.
            private int recursionDepth; 

            #endregion Fields.

            #region Constructors. 

            /// Initializes a new . 
            /// Service with data and configuration. 
            /// Parameters for the current "it" context.
            /// Expression to parse. 
            internal ExpressionParser(IDataService service, ParameterExpression parameterForIt, string expression)
            {
                Debug.Assert(service != null, "service != null");
                Debug.Assert(expression != null, "expression != null"); 
                Debug.Assert(parameterForIt != null, "parameterForIt != null");
 
                this.service = service; 
                this.provider = service.Provider;
                this.nullPropagationRequired = this.provider.NullPropagationRequired; 
                this.literals = new Dictionary();
                this.it = parameterForIt;
                this.lexer = new ExpressionLexer(expression);
            } 

            #endregion Constructors. 
 
            /// Current token being processed.
            private Token CurrentToken 
            {
                get { return this.lexer.CurrentToken; }
                set { this.lexer.CurrentToken = value; }
            } 

            /// Parses the text expression for a .Where method invocation. 
            /// The parsed expression. 
            internal Expression ParseWhere()
            { 
                int exprPos = this.lexer.Position;
                Expression expr = this.ParseExpression();
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(expr)) 
                {
                    expr = Expression.Convert(expr, typeof(bool)); 
                } 
                else
#endif 
                    if (IsNullConstant(expr))
                {
                    expr = falseLiteral;
                } 
                else if (expr.Type == typeof(bool?))
                { 
                    Expression test = Expression.Equal(expr, Expression.Constant(null, typeof(bool?))); 
                    expr = Expression.Condition(test, falseLiteral, Expression.Property(expr, "Value"));
                } 
                else if (expr.Type != typeof(bool))
                {
                    throw ParseError(Strings.RequestQueryParser_ExpressionTypeMismatch(this.GetTypeName(typeof(bool)), exprPos));
                } 

                this.lexer.ValidateToken(TokenId.End); 
                Debug.Assert(expr != null, "expr != null"); 
                Debug.Assert(expr.Type == typeof(bool), "expr.Type(" + expr.Type + ") == typeof(bool)");
                return expr; 
            }

            /// Parses the text expression for ordering.
            /// An enumeration of orderings. 
            internal IEnumerable ParseOrdering()
            { 
                List orderings = new List(); 
                while (true)
                { 
                    Expression expr = this.ParseExpression();
                    bool ascending = true;
                    if (this.TokenIdentifierIs(ExpressionConstants.KeywordAscending))
                    { 
                        this.lexer.NextToken();
                    } 
                    else if (this.TokenIdentifierIs(ExpressionConstants.KeywordDescending)) 
                    {
                        this.lexer.NextToken(); 
                        ascending = false;
                    }

                    orderings.Add(new DynamicOrdering(expr, ascending)); 
                    if (this.CurrentToken.Id != TokenId.Comma)
                    { 
                        break; 
                    }
 
                    this.lexer.NextToken();
                }

                this.ValidateToken(TokenId.End); 
                return orderings;
            } 
 
            /// Compares two byte arrays for equality.
            /// First byte array.Second byte array. 
            /// true if the arrays are equal; false otherwise.
            private static bool ByteArraysEqual(byte[] b0, byte[] b1)
            {
                if (b0 == b1) 
                {
                    return true; 
                } 

                if (b0 == null || b1 == null) 
                {
                    return false;
                }
 
                if (b0.Length != b1.Length)
                { 
                    return false; 
                }
 
                for (int i = 0; i < b0.Length; i++)
                {
                    if (b0[i] != b1[i])
                    { 
                        return false;
                    } 
                } 

                return true; 
            }

            /// Compares two byte arrays for equality.
            /// First byte array.Second byte array. 
            /// true if the arrays are not equal; false otherwise.
            private static bool ByteArraysNotEqual(byte[] b0, byte[] b1) 
            { 
                return !ByteArraysEqual(b0, b1);
            } 

            /// Gets a non-nullable version of the specified type.
            /// Type to get non-nullable version for.
            ///  
            ///  if type is a reference type or a
            /// non-nullable type; otherwise, the underlying value type. 
            ///  
            private static Type GetNonNullableType(Type type)
            { 
                return Nullable.GetUnderlyingType(type) ?? type;
            }

            /// Checks whether the specified type is a signed integral type. 
            /// Type to check.
            /// true if  is a signed integral type; false otherwise. 
            private static bool IsSignedIntegralType(Type type) 
            {
                return GetNumericTypeKind(type) == NumericTypeSignedIntegral; 
            }

            /// Checks whether the specified type is an unsigned integral type.
            /// Type to check. 
            /// true if  is an unsigned integral type; false otherwise.
            private static bool IsUnsignedIntegralType(Type type) 
            { 
                return GetNumericTypeKind(type) == NumericTypeUnsignedIntegral;
            } 

            /// Gets a flag for the numeric kind of type.
            /// Type to get numeric kind for.
            ///  
            /// One of NumericTypeNotNumeric; NumericTypeNotIntegral if it's char,
            /// single, double or decimal; NumericTypeSignedIntegral, or NumericTypeUnsignedIntegral. 
            ///  
            private static int GetNumericTypeKind(Type type)
            { 
                type = GetNonNullableType(type);
                Debug.Assert(!type.IsEnum, "!type.IsEnum");
                switch (Type.GetTypeCode(type))
                { 
                    case TypeCode.Char:
                    case TypeCode.Single: 
                    case TypeCode.Double: 
                    case TypeCode.Decimal:
                        return NumericTypeNotIntegral; 
                    case TypeCode.SByte:
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64: 
                        return NumericTypeSignedIntegral;
                    case TypeCode.Byte: 
                        return NumericTypeUnsignedIntegral; 
                    default:
                        return NumericTypeNotNumeric; 
                }
            }

            /// Checks whether type is a (possibly nullable) enumeration type. 
            /// Type to check.
            /// true if type is an enumeration or a nullable enumeration; false otherwise. 
            private static bool IsEnumType(Type type) 
            {
                return GetNonNullableType(type).IsEnum; 
            }

            /// Returns an object that can enumerate the specified type and its supertypes.
            /// Type to based enumeration on. 
            /// An object that can enumerate the specified type and its supertypes.
            private static IEnumerable SelfAndBaseTypes(Type type) 
            { 
                if (type.IsInterface)
                { 
                    List types = new List();
                    AddInterface(types, type);
                    return types;
                } 

                return SelfAndBaseClasses(type); 
            } 

            /// Returns an object that can enumerate the specified type and its supertypes. 
            /// Type to based enumeration on.
            /// An object that can enumerate the specified type and its supertypes.
            private static IEnumerable SelfAndBaseClasses(Type type)
            { 
                while (type != null)
                { 
                    yield return type; 
                    type = type.BaseType;
                } 
            }

            /// Adds an interface type to a list of types, including inherited interfaces.
            /// Types list ot add to. 
            /// Interface type to add.
            private static void AddInterface(List types, Type type) 
            { 
                if (!types.Contains(type))
                { 
                    types.Add(type);
                    foreach (Type t in type.GetInterfaces())
                    {
                        AddInterface(types, t); 
                    }
                } 
            } 

            /// Finds the best applicable methods from the specified array that match the arguments. 
            /// Candidate methods.
            /// Argument expressions.
            /// Best applicable methods.
            private static MethodData[] FindBestApplicableMethods(MethodData[] applicable, Expression[] args) 
            {
                Debug.Assert(applicable != null, "applicable != null"); 
 
                List result = new List();
                foreach (MethodData method in applicable) 
                {
                    bool betterThanAllOthers = true;
                    foreach (MethodData otherMethod in applicable)
                    { 
                        if (otherMethod != method && IsBetterThan(args, otherMethod, method))
                        { 
                            betterThanAllOthers = false; 
                            break;
                        } 
                    }

                    if (betterThanAllOthers)
                    { 
                        result.Add(method);
                    } 
                } 

                return result.ToArray(); 
            }

            /// Parses the specified text into a number.
            /// Text to parse. 
            /// Type to parse into.
            /// The parsed number. 
            private static object ParseNumber(string text, Type type) 
            {
                TypeCode tc = Type.GetTypeCode(GetNonNullableType(type)); 
                switch (tc)
                {
                    case TypeCode.SByte:
                        sbyte sb; 
                        if (sbyte.TryParse(text, out sb))
                        { 
                            return sb; 
                        }
 
                        break;
                    case TypeCode.Byte:
                        byte b;
                        if (byte.TryParse(text, out b)) 
                        {
                            return b; 
                        } 

                        break; 
                    case TypeCode.Int16:
                        short s;
                        if (short.TryParse(text, out s))
                        { 
                            return s;
                        } 
 
                        break;
                    case TypeCode.Int32: 
                        int i;
                        if (int.TryParse(text, out i))
                        {
                            return i; 
                        }
 
                        break; 
                    case TypeCode.Int64:
                        long l; 
                        if (long.TryParse(text, out l))
                        {
                            return l;
                        } 

                        break; 
                    case TypeCode.Single: 
                        float f;
                        if (float.TryParse(text, out f)) 
                        {
                            return f;
                        }
 
                        break;
                    case TypeCode.Double: 
                        double d; 
                        if (double.TryParse(text, out d))
                        { 
                            return d;
                        }

                        break; 
                    case TypeCode.Decimal:
                        decimal e; 
                        if (decimal.TryParse(text, out e)) 
                        {
                            return e; 
                        }

                        break;
                } 

                return null; 
            } 

            /// Checks whether the source type is compatible with the value type. 
            /// Source type.
            /// Target type.
            /// true if source can be used in place of target; false otherwise.
            private static bool IsCompatibleWith(Type source, Type target) 
            {
                if (source == target) 
                { 
                    return true;
                } 

                if (!target.IsValueType)
                {
                    return target.IsAssignableFrom(source); 
                }
 
                Type sourceType = GetNonNullableType(source); 
                Type targetType = GetNonNullableType(target);
 
                //// This rule stops the parser from considering nullable types as incompatible
                //// with non-nullable types. We have however implemented this rule because we just
                //// access underlying rules. C# requires an explicit .Value access, and EDM has no
                //// nullablity on types and (at the model level) implements null propagation. 
                ////
                //// if (sourceType != source && targetType == target) 
                //// { 
                ////     return false;
                //// } 

                TypeCode sourceCode = sourceType.IsEnum ? TypeCode.Object : Type.GetTypeCode(sourceType);
                TypeCode targetCode = targetType.IsEnum ? TypeCode.Object : Type.GetTypeCode(targetType);
                switch (sourceCode) 
                {
                    case TypeCode.SByte: 
                        switch (targetCode) 
                        {
                            case TypeCode.SByte: 
                            case TypeCode.Int16:
                            case TypeCode.Int32:
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true; 
                        }
 
                        break;
                    case TypeCode.Byte:
                        switch (targetCode)
                        { 
                            case TypeCode.Byte:
                            case TypeCode.Int16: 
                            case TypeCode.Int32: 
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                                return true;
                        } 

                        break; 
                    case TypeCode.Int16: 
                        switch (targetCode)
                        { 
                            case TypeCode.Int16:
                            case TypeCode.Int32:
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true; 
                        }
 
                        break;
                    case TypeCode.Int32:
                        switch (targetCode)
                        { 
                            case TypeCode.Int32:
                            case TypeCode.Int64: 
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true;
                        }

                        break; 
                    case TypeCode.Int64:
                        switch (targetCode) 
                        { 
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                                return true;
                        } 

                        break; 
                    case TypeCode.Single: 
                        switch (targetCode)
                        { 
                            case TypeCode.Single:
                            case TypeCode.Double:
                                return true;
                        } 

                        break; 
                    default: 
                        if (sourceType == targetType)
                        { 
                            return true;
                        }

                        break; 
                }
 
                // Anything can be converted to something that's *exactly* an object. 
#if ASTORIA_OPEN_OBJECT
                if (target == typeof(object)) 
                {
                    return true;
                }
#endif 

                return false; 
            } 

            ///  
            /// Checks whether one type list is a better fit than other for the
            /// specified expressions.
            /// 
            /// Expressions for arguments. 
            /// First type list to check.
            /// Second type list to check. 
            ///  
            /// true if  has better parameter matching than .
            ///  
            private static bool IsBetterThan(Expression[] args, IEnumerable firstCandidate, IEnumerable secondCandidate)
            {
                bool better = false;
 
                using (IEnumerator first = firstCandidate.GetEnumerator())
                using (IEnumerator second = secondCandidate.GetEnumerator()) 
                { 
                    for (int i = 0; i < args.Length; i++)
                    { 
                        first.MoveNext();
                        second.MoveNext();
                        int c = CompareConversions(args[i].Type, first.Current, second.Current);
                        if (c < 0) 
                        {
                            return false; 
                        } 
                        else if (c > 0)
                        { 
                            better = true;
                        }
                    }
                } 

                return better; 
            } 

            ///  
            /// Checks whether one method is a better fit than other for the
            /// specified expressions.
            /// 
            /// Expressions for arguments. 
            /// First method to check.
            /// Second method to check. 
            ///  
            /// true if  has better parameter matching than .
            ///  
            private static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
            {
                Debug.Assert(args != null, "args != null");
                Debug.Assert(m1 != null, "m1 != null"); 
                Debug.Assert(m2 != null, "m2 != null");
                return IsBetterThan(args, m1.ParameterTypes, m2.ParameterTypes); 
            } 

            /// Checks which conversion is better. 
            /// Source type.
            /// First candidate type to convert to.
            /// Second candidate type to convert to.
            ///  
            /// Return 1 if s -> t1 is a better conversion than s -> t2
            /// Return -1 if s -> t2 is a better conversion than s -> t1 
            /// Return 0 if neither conversion is better 
            /// 
            private static int CompareConversions(Type source, Type targetA, Type targetB) 
            {
                // If both types are exactly the same, there is no preference.
                if (targetA == targetB)
                { 
                    return 0;
                } 
 
                // Look for exact matches.
                if (source == targetA) 
                {
                    return 1;
                }
                else if (source == targetB) 
                {
                    return -1; 
                } 

                // If one is compatible and the other is not, choose the compatible type. 
                bool compatibleT1AndT2 = IsCompatibleWith(targetA, targetB);
                bool compatibleT2AndT1 = IsCompatibleWith(targetB, targetA);
                if (compatibleT1AndT2 && !compatibleT2AndT1)
                { 
                    return 1;
                } 
                else if (compatibleT2AndT1 && !compatibleT1AndT2) 
                {
                    return -1; 
                }

                // Prefer to keep the original nullability.
                bool sourceNullable = IsNullableType(source); 
                bool typeNullableA = IsNullableType(targetA);
                bool typeNullableB = IsNullableType(targetB); 
                if (sourceNullable == typeNullableA && sourceNullable != typeNullableB) 
                {
                    return 1; 
                }
                else if (sourceNullable != typeNullableA && sourceNullable == typeNullableB)
                {
                    return -1; 
                }
 
                // Prefer signed to unsigned. 
                if (IsSignedIntegralType(targetA) && IsUnsignedIntegralType(targetB))
                { 
                    return 1;
                }
                else if (IsSignedIntegralType(targetB) && IsUnsignedIntegralType(targetA))
                { 
                    return -1;
                } 
 
                // Prefer non-object to object.
                if (targetA != typeof(object) && targetB == typeof(object)) 
                {
                    return 1;
                }
                else if (targetB != typeof(object) && targetA == typeof(object)) 
                {
                    return -1; 
                } 

                return 0; 
            }

            /// Generates an Equal expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression. 
            private static Expression GenerateEqual(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                {
                    return LateBoundMethods.EqualExpression(left, right);
                } 
#endif
 
                if (left.Type == typeof(byte[])) 
                {
                    MethodInfo byteArrayCompareMethod = typeof(ExpressionParser).GetMethod("ByteArraysEqual", BindingFlags.NonPublic | BindingFlags.Static); 
                    return Expression.Equal(left, right, false, byteArrayCompareMethod);
                }

                return Expression.Equal(left, right); 
            }
 
            /// Generates a NotEqual expression. 
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateNotEqual(Expression left, Expression right)
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.NotEqualExpression(left, right); 
                }
#endif 

                if (left.Type == typeof(byte[]))
                {
                    MethodInfo byteArrayCompareMethod = typeof(ExpressionParser).GetMethod("ByteArraysNotEqual", BindingFlags.NonPublic | BindingFlags.Static); 
                    return Expression.NotEqual(left, right, false, byteArrayCompareMethod);
                } 
 
                return Expression.NotEqual(left, right);
            } 

            /// Generates a GreaterThan comparison expression.
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateGreaterThan(Expression left, Expression right) 
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                {
                    return LateBoundMethods.GreaterThanExpression(left, right);
                }
#endif 

                if (left.Type == typeof(string)) 
                { 
                    return Expression.GreaterThan(left, right, false, GetStringCompareMethod("StringGreaterThanMethod"));
                } 

                return Expression.GreaterThan(left, right);
            }
 
            /// Generates a GreaterThanOrEqual comparsion expression.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateGreaterThanEqual(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.GreaterThanOrEqualExpression(left, right);
                } 
#endif 

                if (left.Type == typeof(string)) 
                {
                    return Expression.GreaterThanOrEqual(left, right, false, GetStringCompareMethod("StringGreaterThanOrEqualMethod"));
                }
 
                return Expression.GreaterThanOrEqual(left, right);
            } 
 
            /// Generates a LessThan comparsion expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression.
            private static Expression GenerateLessThan(Expression left, Expression right)
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                { 
                    return LateBoundMethods.LessThanExpression(left, right);
                } 
#endif

                if (left.Type == typeof(string))
                { 
                    return Expression.LessThan(left, right, false, GetStringCompareMethod("StringLessThanMethod"));
                } 
 
                return Expression.LessThan(left, right);
            } 

            /// Generates a LessThanOrEqual comparsion expression.
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateLessThanEqual(Expression left, Expression right) 
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                {
                    return LateBoundMethods.LessThanOrEqualExpression(left, right);
                }
#endif 

                if (left.Type == typeof(string)) 
                { 
                    return Expression.LessThanOrEqual(left, right, false, GetStringCompareMethod("StringLessThanOrEqualMethod"));
                } 

                return Expression.LessThanOrEqual(left, right);
            }
 
            /// Generates an addition expression.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateAdd(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.AddExpression(left, right);
                } 
#endif 

                return Expression.Add(left, right); 
            }

            /// Generates a subtract expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression. 
            private static Expression GenerateSubtract(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                {
                    return LateBoundMethods.SubtractExpression(left, right);
                } 
#endif
 
                return Expression.Subtract(left, right); 
            }
 
            /// Gets a static method to compare strings.
            /// Name of method.
            /// The  for the method.
            private static MethodInfo GetStringCompareMethod(string methodName) 
            {
                Debug.Assert(methodName != null, "methodName != null"); 
                MethodInfo result = typeof(ExpressionParser).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static); 
                Debug.Assert(result != null, "result != null");
                return result; 
            }

#if ASTORIA_OPEN_OBJECT
            ///  
            /// Checks whether the specified  is part of an open property expression.
            ///  
            /// Non-null  to check. 
            /// true if  is based on an open property; false otherwise.
            private static bool IsOpenPropertyExpression(Expression expression) 
            {
                Debug.Assert(expression != null, "expression != null");
                return expression != NullLiteral && expression.Type == typeof(object);
            } 
#endif
 
            /// Checks whether the left string is less than or equal to the right string. 
            /// Left value.Right value.
            /// true if the left string is less than or equal to the right string. 
            private static bool StringLessThanOrEqualMethod(string left, string right)
            {
                return string.CompareOrdinal(left, right) <= 0;
            } 

            /// Checks whether the left string is less than the right string. 
            /// Left value.Right value. 
            /// true if the left string is less than the right string.
            private static bool StringLessThanMethod(string left, string right) 
            {
                return string.CompareOrdinal(left, right) < 0;
            }
 
            /// Checks whether the left string is greater than or equal to the right string.
            /// Left value.Right value. 
            /// true if the left string is greater than or equal to the right string. 
            private static bool StringGreaterThanOrEqualMethod(string left, string right)
            { 
                return string.CompareOrdinal(left, right) >= 0;
            }

            /// Checks whether the left string is greater than the right string. 
            /// Left value.Right value.
            /// true if the left string is greater than the right string. 
            private static bool StringGreaterThanMethod(string left, string right) 
            {
                return string.CompareOrdinal(left, right) > 0; 
            }

            /// Gets a static method by name.
            /// Name of method to get. 
            /// Left expression to resolve method from and to use as argument.
            /// Right expression. 
            /// The method. 
            private static MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
            { 
                return left.Type.GetMethod(methodName, new Type[] { left.Type, right.Type });
            }

            /// Generates a static method call. 
            /// Method name.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) 
            {
                return Expression.Call(null, GetStaticMethod(methodName, left, right), new Expression[] { left, right });
            }
 
            /// Creates an exception for a parse error.
            /// Message text. 
            /// A new Exception. 
            private static Exception ParseError(string message)
            { 
                return DataServiceException.CreateSyntaxError(message);
            }

            /// Checks that the given token has the specified identifier. 
            /// Token to check
            /// Identifier to check. 
            /// true if  is an identifier with the specified text. 
            private static bool TokenIdentifierIs(Token token, string id)
            { 
                return token.Id == TokenId.Identifier && String.Equals(id, token.Text, StringComparison.OrdinalIgnoreCase);
            }

            #region Parsing. 

            /// Handles a ?: operator - not supported. 
            /// The parsed expression. 
            private Expression ParseExpression()
            { 
                this.RecurseEnter();
                Expression expr = this.ParseLogicalOr();
                this.RecurseLeave();
                return expr; 
            }
 
            /// Handles or operator. 
            /// The parsed expression.
            private Expression ParseLogicalOr() 
            {
                this.RecurseEnter();
                Expression left = this.ParseLogicalAnd();
                while (this.TokenIdentifierIs(ExpressionConstants.KeywordOr)) 
                {
                    Token op = this.CurrentToken; 
                    this.lexer.NextToken(); 
                    Expression right = this.ParseLogicalAnd();
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.ILogicalSignatures), op.Text, ref left, ref right, op.Position); 
#if ASTORIA_OPEN_OBJECT
                    if (left.Type == typeof(object) || right.Type == typeof(object))
                    {
                        left = LateBoundMethods.OrElseExpression(left, right); 
                        if (left == null)
                        { 
                            throw ParseError(Strings.RequestQueryParser_BooleanExpressionsExpectedFor(op.Text)); 
                        }
                    } 
                    else
#endif
                    {
                        left = Expression.OrElse(left, right); 
                    }
                } 
 
                this.RecurseLeave();
                return left; 
            }

            /// Handles and operator.
            /// The parsed expression. 
            private Expression ParseLogicalAnd()
            { 
                this.RecurseEnter(); 
                Expression left = this.ParseComparison();
                while (this.TokenIdentifierIs(ExpressionConstants.KeywordAnd)) 
                {
                    Token op = this.CurrentToken;
                    this.lexer.NextToken();
                    Expression right = this.ParseComparison(); 
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.ILogicalSignatures), op.Text, ref left, ref right, op.Position);
#if ASTORIA_OPEN_OBJECT 
                    if (left.Type == typeof(object) || right.Type == typeof(object)) 
                    {
                        left = LateBoundMethods.AndAlsoExpression(left, right); 
                        if (left == null)
                        {
                            throw ParseError(Strings.RequestQueryParser_BooleanExpressionsExpectedFor(op.Text));
                        } 
                    }
                    else 
#endif 
                    {
                        left = Expression.AndAlso(left, right); 
                    }
                }

                this.RecurseLeave(); 
                return left;
            } 
 
            /// Handles eq, ne, lt, gt, le, ge operators.
            /// The parsed expression. 
            private Expression ParseComparison()
            {
                this.RecurseEnter();
                Expression left = this.ParseAdditive(); 
                while (this.CurrentToken.IsComparisonOperator)
                { 
                    Token op = this.CurrentToken; 
                    this.lexer.NextToken();
                    Expression right = this.ParseAdditive(); 
                    bool equality = op.IsEqualityOperator;

                    if (equality && !left.Type.IsValueType && !right.Type.IsValueType)
                    { 
                        if (left.Type != right.Type)
                        { 
                            if (IsNullConstant(left)) 
                            {
                                left = Expression.Constant(null, right.Type); 
                            }
                            else if (IsNullConstant(right))
                            {
                                right = Expression.Constant(null, left.Type); 
                            }
                            else if (left.Type.IsAssignableFrom(right.Type)) 
                            { 
                                right = Expression.Convert(right, left.Type);
                            } 
                            else if (right.Type.IsAssignableFrom(left.Type))
                            {
                                left = Expression.Convert(left, right.Type);
                            } 
                            else
                            { 
                                throw this.IncompatibleOperandsError(op.Text, left, right, op.Position); 
                            }
                        } 
                    }
                    else if (left == NullLiteral || right == NullLiteral)
                    {
                        if (!equality) 
                        {
                            throw ParseError( 
                                Strings.RequestQueryParser_NullOperatorUnsupported(op.Text, op.Position, this.lexer.ExpressionText)); 
                        }
 
                        // Because we don't have an explicit "is null" check, literal comparisons
                        // to null are special.
                        if (!TypeAllowsNull(left.Type))
                        { 
                            left = Expression.Convert(left, typeof(Nullable<>).MakeGenericType(left.Type));
                        } 
                        else if (!TypeAllowsNull(right.Type)) 
                        {
                            right = Expression.Convert(right, typeof(Nullable<>).MakeGenericType(right.Type)); 
                        }
                    }
                    else
                    { 
                        // Enums should be checked here for promotion when supported, but they aren't in this version.
                        Debug.Assert(!IsEnumType(left.Type), "!IsEnumType(left.Type)"); 
                        Debug.Assert(!IsEnumType(right.Type), "!IsEnumType(right.Type)"); 

                        Type signatures = equality ? typeof(OperationSignatures.IEqualitySignatures) : typeof(OperationSignatures.IRelationalSignatures); 
                        this.CheckAndPromoteOperands(signatures, op.Text, ref left, ref right, op.Position);
                    }

                    Debug.Assert(op.Id == TokenId.Identifier, "op.id == TokenId.Identifier"); 
                    switch (op.Text)
                    { 
                        case ExpressionConstants.KeywordEqual: 
                            left = GenerateEqual(left, right);
                            break; 
                        case ExpressionConstants.KeywordNotEqual:
                            left = GenerateNotEqual(left, right);
                            break;
                        case ExpressionConstants.KeywordGreaterThan: 
                            left = GenerateGreaterThan(left, right);
                            break; 
                        case ExpressionConstants.KeywordGreaterThanOrEqual: 
                            left = GenerateGreaterThanEqual(left, right);
                            break; 
                        case ExpressionConstants.KeywordLessThan:
                            left = GenerateLessThan(left, right);
                            break;
                        case ExpressionConstants.KeywordLessThanOrEqual: 
                            left = GenerateLessThanEqual(left, right);
                            break; 
                    } 
                }
 
                this.RecurseLeave();
                return left;
            }
 
            /// Handles +, -, & operators (& for string concat, not supported).
            /// The parsed expression. 
            private Expression ParseAdditive() 
            {
                this.RecurseEnter(); 
                Expression left = this.ParseMultiplicative();
                while (this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordAdd) ||
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordSub))
                { 
                    Token op = this.CurrentToken;
                    this.lexer.NextToken(); 
                    Expression right = this.ParseMultiplicative(); 
                    if (op.IdentifierIs(ExpressionConstants.KeywordAdd))
                    { 
                        this.CheckAndPromoteOperands(typeof(OperationSignatures.IAddSignatures), op.Text, ref left, ref right, op.Position);
                        left = GenerateAdd(left, right);
                    }
                    else 
                    {
                        Debug.Assert(ExpressionParser.TokenIdentifierIs(op, ExpressionConstants.KeywordSub), "ExpressionParser.TokenIdentifierIs(op, ExpressionConstants.KeywordSub)"); 
                        this.CheckAndPromoteOperands(typeof(OperationSignatures.ISubtractSignatures), op.Text, ref left, ref right, op.Position); 
                        left = GenerateSubtract(left, right);
                    } 
                }

                this.RecurseLeave();
                return left; 
            }
 
            /// Handles mul, div, mod operators. 
            /// The parsed expression.
            private Expression ParseMultiplicative() 
            {
                this.RecurseEnter();
                Expression left = this.ParseUnary();
                while (this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordMultiply) || 
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordDivide) ||
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordModulo)) 
                { 
                    Token op = this.CurrentToken;
                    this.lexer.NextToken(); 
                    Expression right = this.ParseUnary();
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.IArithmeticSignatures), op.Text, ref left, ref right, op.Position);
                    if (op.IdentifierIs(ExpressionConstants.KeywordMultiply))
                    { 
#if ASTORIA_OPEN_OBJECT
                        if (left.Type == typeof(object) || right.Type == typeof(object)) 
                        { 
                            left = LateBoundMethods.MultiplyExpression(left, right);
                        } 
                        else
#endif
                        {
                            left = Expression.Multiply(left, right); 
                        }
                    } 
                    else if (op.IdentifierIs(ExpressionConstants.KeywordDivide)) 
                    {
#if ASTORIA_OPEN_OBJECT 
                        if (left.Type == typeof(object) || right.Type == typeof(object))
                        {
                            left = LateBoundMethods.DivideExpression(left, right);
                        } 
                        else
#endif 
                        { 
                            left = Expression.Divide(left, right);
                        } 
                    }
                    else
                    {
                        Debug.Assert(op.IdentifierIs(ExpressionConstants.KeywordModulo), "op.IdentifierIs(ExpressionConstants.KeywordModulo)"); 
#if ASTORIA_OPEN_OBJECT
                        if (left.Type == typeof(object) || right.Type == typeof(object)) 
                        { 
                            left = LateBoundMethods.ModuloExpression(left, right);
                        } 
                        else
#endif
                        {
                            left = Expression.Modulo(left, right); 
                        }
                    } 
                } 

                this.RecurseLeave(); 
                return left;
            }

            /// Handles -, not unary operators. 
            /// The parsed expression.
            private Expression ParseUnary() 
            { 
                this.RecurseEnter();
                if (this.CurrentToken.Id == TokenId.Minus || this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordNot)) 
                {
                    Token op = this.CurrentToken;
                    this.lexer.NextToken();
                    if (op.Id == TokenId.Minus && (ExpressionLexer.IsNumeric(this.CurrentToken.Id))) 
                    {
                        Token numberLiteral = this.CurrentToken; 
                        numberLiteral.Text = "-" + numberLiteral.Text; 
                        numberLiteral.Position = op.Position;
                        this.CurrentToken = numberLiteral; 
                        this.RecurseLeave();
                        return this.ParsePrimary();
                    }
 
                    Expression expr = this.ParseUnary();
                    if (op.Id == TokenId.Minus) 
                    { 
                        this.CheckAndPromoteOperand(typeof(OperationSignatures.INegationSignatures), op.Text, ref expr, op.Position);
#if ASTORIA_OPEN_OBJECT 
                        if (expr.Type == typeof(object))
                        {
                            expr = LateBoundMethods.NegateExpression(expr);
                        } 
                        else
#endif 
                        { 
                            expr = Expression.Negate(expr);
                        } 
                    }
                    else
                    {
                        this.CheckAndPromoteOperand(typeof(OperationSignatures.INotSignatures), op.Text, ref expr, op.Position); 
#if ASTORIA_OPEN_OBJECT
                        if (expr.Type == typeof(object)) 
                        { 
                            expr = LateBoundMethods.NotExpression(expr);
                        } 
                        else
#endif
                        if (expr.Type == typeof(bool) || expr.Type == typeof(Nullable))
                        { 
                            // Expression.Not will take numerics and apply '~' to them, thus the extra check here.
                            expr = Expression.Not(expr); 
                        } 
                        else
                        { 
                            throw ParseError(Strings.RequestQueryParser_NotDoesNotSupportType(expr.Type));
                        }
                    }
 
                    this.RecurseLeave();
                    return expr; 
                } 

                this.RecurseLeave(); 
                return this.ParsePrimary();
            }

            /// Handles primary expressions. 
            /// The parsed expression.
            private Expression ParsePrimary() 
            { 
                this.RecurseEnter();
                Expression expr = this.ParsePrimaryStart(); 
                while (true)
                {
                    if (this.CurrentToken.Id == TokenId.Slash)
                    { 
                        this.lexer.NextToken();
                        expr = this.ParseMemberAccess(expr); 
                    } 
                    else
                    { 
                        break;
                    }
                }
 
                this.RecurseLeave();
                return expr; 
            } 

            /// Handles the start of primary expressions. 
            /// The parsed expression.
            private Expression ParsePrimaryStart()
            {
                switch (this.CurrentToken.Id) 
                {
                    case TokenId.BooleanLiteral: 
                        return this.ParseTypedLiteral(typeof(bool), XmlConstants.EdmBooleanTypeName); 
                    case TokenId.DateTimeLiteral:
                        return this.ParseTypedLiteral(typeof(DateTime), XmlConstants.EdmDateTimeTypeName); 
                    case TokenId.DecimalLiteral:
                        return this.ParseTypedLiteral(typeof(decimal), XmlConstants.EdmDecimalTypeName);
                    case TokenId.NullLiteral:
                        return this.ParseNullLiteral(); 
                    case TokenId.Identifier:
                        return this.ParseIdentifier(); 
                    case TokenId.StringLiteral: 
                        return this.ParseTypedLiteral(typeof(string), XmlConstants.EdmStringTypeName);
                    case TokenId.Int64Literal: 
                        return this.ParseTypedLiteral(typeof(Int64), XmlConstants.EdmInt64TypeName);
                    case TokenId.IntegerLiteral:
                        return this.ParseTypedLiteral(typeof(Int32), XmlConstants.EdmInt32TypeName);
                    case TokenId.DoubleLiteral: 
                        return this.ParseTypedLiteral(typeof(double), XmlConstants.EdmDoubleTypeName);
                    case TokenId.SingleLiteral: 
                        return this.ParseTypedLiteral(typeof(Single), XmlConstants.EdmSingleTypeName); 
                    case TokenId.GuidLiteral:
                        return this.ParseTypedLiteral(typeof(Guid), XmlConstants.EdmGuidTypeName); 
                    case TokenId.BinaryLiteral:
                        return this.ParseTypedLiteral(typeof(byte[]), XmlConstants.EdmBinaryTypeName);
                    case TokenId.OpenParen:
                        return this.ParseParenExpression(); 
                    default:
                        throw ParseError(Strings.RequestQueryParser_ExpressionExpected(this.CurrentToken.Position)); 
                } 
            }
 
            /// Handles parenthesized expressions.
            /// The parsed expression.
            private Expression ParseParenExpression()
            { 
                if (this.CurrentToken.Id != TokenId.OpenParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_OpenParenExpected(this.CurrentToken.Position)); 
                }
 
                this.lexer.NextToken();
                Expression e = this.ParseExpression();
                if (this.CurrentToken.Id != TokenId.CloseParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_CloseParenOrOperatorExpected(this.CurrentToken.Position));
                } 
 
                this.lexer.NextToken();
                return e; 
            }

            /// Handles identifiers.
            /// The parsed expression. 
            private Expression ParseIdentifier()
            { 
                this.ValidateToken(TokenId.Identifier); 
                bool identifierIsFunction = this.lexer.PeekNextToken().Id == TokenId.OpenParen;
                if (identifierIsFunction) 
                {
                    return this.ParseIdentifierAsFunction();
                }
                else 
                {
                    return this.ParseMemberAccess(this.it); 
                } 
            }
 
            /// Handles identifiers which have been recognized as functions.
            /// The parsed expression.
            private Expression ParseIdentifierAsFunction()
            { 
                FunctionDescription[] functionDescriptions;
                Token functionToken = this.CurrentToken; 
                if (!functions.TryGetValue(functionToken.Text, out functionDescriptions)) 
                {
                    throw ParseError(Strings.RequestQueryParser_UnknownFunction(functionToken.Text, functionToken.Position)); 
                }

                this.lexer.NextToken();
                Expression[] originalArguments = this.ParseArgumentList(); 
                Expression[] arguments = this.nullPropagationRequired ? originalArguments : (Expression[])originalArguments.Clone();
                FunctionDescription function = this.FindBestFunction(functionDescriptions, ref arguments); 
                if (function == null) 
                {
                    string message = Strings.RequestQueryParser_NoApplicableFunction( 
                        functionToken.Text,
                        functionToken.Position,
                        FunctionDescription.BuildSignatureList(functionToken.Text, functionDescriptions));
                    throw ParseError(message); 
                }
 
                // Special case for null propagation - we never strip nullability from expressions. 
                if (this.nullPropagationRequired && function.IsTypeCast)
                { 
                    Expression typeExpression = arguments[arguments.Length - 1];
                    Debug.Assert(typeExpression != null, "typeExpression != null -- otherwise function finding failed.");
                    Debug.Assert(typeExpression.Type == typeof(Type), "typeExpression.Type == typeof(Type) -- last argument is always type.");
                    Type castTargetType = (Type)((ConstantExpression)typeExpression).Value; 
                    if (!TypeAllowsNull(castTargetType))
                    { 
                        arguments[arguments.Length - 1] = Expression.Constant(typeof(Nullable<>).MakeGenericType(castTargetType)); 
                    }
                } 

                Expression result = function.ConversionFunction(this.it, arguments);
                if (this.nullPropagationRequired && !function.IsTypeCheck && !function.IsTypeCast)
                { 
                    Debug.Assert(
                        originalArguments != arguments, 
                        "originalArguments != arguments -- arguments should have been cloned"); 
                    Debug.Assert(
                        originalArguments.Length == arguments.Length, 
                        "originalArguments.Length == arguments.Length -- arguments should not be added/removed");
                    for (int i = 0; i < originalArguments.Length; i++)
                    {
                        result = this.ConsiderNullPropagation(originalArguments[i], result); 
                    }
                } 
 
                return result;
            } 

            /// Handles boolean literals.
            /// The parsed expression.
            private Expression ParseBooleanLiteral() 
            {
                Debug.Assert(this.CurrentToken.Id == TokenId.BooleanLiteral, "this.CurrentToken.Id == TokenId.BooleanLiteral"); 
                string originalText = this.CurrentToken.Text; 
                this.lexer.NextToken();
                if (originalText == ExpressionConstants.KeywordTrue) 
                {
                    return trueLiteral;
                }
                else 
                {
                    Debug.Assert(originalText == ExpressionConstants.KeywordFalse, "originalText == ExpressionConstants.KeywordFalse"); 
                    return falseLiteral; 
                }
            } 

            /// Handles typed literals.
            /// Expected type to be parsed.
            /// Expected type name. 
            /// The constants expression produced by building the given literal.
            private Expression ParseTypedLiteral(Type targetType, string targetTypeName) 
            { 
                object targetValue;
                if (!WebConvert.TryKeyStringToPrimitive(this.CurrentToken.Text, targetType, out targetValue)) 
                {
                    string message = Strings.RequestQueryParser_UnrecognizedLiteral(targetTypeName, this.CurrentToken.Text, this.CurrentToken.Position);
                    throw ParseError(message);
                } 

                Expression result = this.CreateLiteral(targetValue, this.CurrentToken.Text); 
                this.lexer.NextToken(); 
                return result;
            } 

            /// Handles 'null' literals.
            /// The parsed expression.
            private Expression ParseNullLiteral() 
            {
                Debug.Assert(this.CurrentToken.Id == TokenId.NullLiteral, "this.CurrentToken.Id == TokenId.NullLiteral"); 
                this.lexer.NextToken(); 
                return NullLiteral;
            } 

            /// Handles member access.
            /// Instance being accessed.
            /// The parsed expression. 
            private Expression ParseMemberAccess(Expression instance)
            { 
                Debug.Assert(instance != null, "instance != null"); 

                Type type = instance.Type; 
                int errorPos = this.lexer.Position;
                string id = this.CurrentToken.GetIdentifier();
                this.lexer.NextToken();
 
                // An open paren here would indicate calling a method in regular C# syntax.
                ResourceProperty property = this.FindProperty(type, id); 
                if (property != null) 
                {
                    // We have a strongly-type property. 
                    Expression result = this.ConsiderNullPropagation(instance, Expression.Property(instance, property.PropertyInfo));
                    if (property.ResourceContainer != null)
                    {
                        Expression filter = DataServiceConfiguration.ComposeQueryInterceptors(this.service, property.ResourceContainer); 
                        if (filter != null)
                        { 
                            // We did null propagation for accessing the property, but we may also need 
                            // to do null propagation on the property value itself (otherwise the interception
                            // lambda needs to check the argument for null, which is probably unexpected). 
                            result = RequestQueryProcessor.ComposePropertyNavigation(
                                result, (LambdaExpression)filter, this.provider.NullPropagationRequired);
                        }
                    } 

                    return result; 
                } 
                else
                { 
                    // Open types can have any members inside them
#if ASTORIA_OPEN_OBJECT

                    if (type == typeof(object) || OpenTypeAttribute.IsOpenType(type)) 
                    {
                        // object LateBoundMethods.GetValue(object, string) 
                        Expression call = 
                            Expression.Call(null /* instance */, LateBoundMethods.GetValueMethodInfo, instance, Expression.Constant(id));
                        return this.ConsiderNullPropagation(instance, call); 
                    }
                    else
#endif
                    { 
                        throw ParseError(Strings.RequestQueryParser_UnknownProperty(id, this.GetTypeName(type), errorPos));
                    } 
                } 
            }
 
            /// Handles argument lists.
            /// The parsed expressions.
            private Expression[] ParseArgumentList()
            { 
                if (this.CurrentToken.Id != TokenId.OpenParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_OpenParenExpected(this.CurrentToken.Position)); 
                }
 
                this.lexer.NextToken();
                Expression[] args = this.CurrentToken.Id != TokenId.CloseParen ? this.ParseArguments() : emptyExpressions;
                if (this.CurrentToken.Id != TokenId.CloseParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_CloseParenOrCommaExpected(this.CurrentToken.Position));
                } 
 
                this.lexer.NextToken();
                return args; 
            }

            /// Handles comma-separated arguments.
            /// The parsed expressions. 
            private Expression[] ParseArguments()
            { 
                List argList = new List(); 
                while (true)
                { 
                    argList.Add(this.ParseExpression());
                    if (this.CurrentToken.Id != TokenId.Comma)
                    {
                        break; 
                    }
 
                    this.lexer.NextToken(); 
                }
 
                return argList.ToArray();
            }

            #endregion Parsing. 

            /// Creates a constant expression with the specified literal. 
            /// Constant value. 
            /// Value text.
            /// The created expression. 
            private Expression CreateLiteral(object value, string text)
            {
                ConstantExpression expr = Expression.Constant(value);
                this.literals.Add(expr, text); 
                return expr;
            } 
 
            /// Finds the best fitting function for the specified arguments.
            /// Functions to consider. 
            /// Arguments; if a best function is found, promoted arguments.
            /// The best fitting function; null if none found or ambiguous.
            private FunctionDescription FindBestFunction(FunctionDescription[] functions, ref Expression[] arguments)
            { 
                Debug.Assert(functions != null, "functions != null");
                List applicableFunctions = new List(functions.Length); 
                List applicablePromotedArguments = new List(functions.Length); 

                // Build a list of applicable functions (and cache their promoted arguments). 
                foreach (FunctionDescription candidate in functions)
                {
                    if (candidate.ParameterTypes.Length != arguments.Length)
                    { 
                        continue;
                    } 
 
                    Expression[] promotedArguments = new Expression[arguments.Length];
                    bool argumentsMatch = true; 
                    for (int i = 0; i < candidate.ParameterTypes.Length; i++)
                    {
                        promotedArguments[i] = this.PromoteExpression(arguments[i], candidate.ParameterTypes[i], true);
                        if (promotedArguments[i] == null) 
                        {
                            argumentsMatch = false; 
                            break; 
                        }
                    } 

                    if (argumentsMatch)
                    {
                        applicableFunctions.Add(candidate); 
                        applicablePromotedArguments.Add(promotedArguments);
                    } 
                } 

                // Return the best applicable function. 
                if (applicableFunctions.Count == 0)
                {
                    // No matching function.
                    return null; 
                }
                else if (applicableFunctions.Count == 1) 
                { 
                    arguments = applicablePromotedArguments[0];
                    return applicableFunctions[0]; 
                }
                else
                {
                    // Find a single function which is better than all others. 
                    int bestFunctionIndex = -1;
                    for (int i = 0; i < applicableFunctions.Count; i++) 
                    { 
                        bool betterThanAllOthers = true;
                        for (int j = 0; j < applicableFunctions.Count; j++) 
                        {
                            if (i != j && IsBetterThan(arguments, applicableFunctions[j].ParameterTypes, applicableFunctions[i].ParameterTypes))
                            {
                                betterThanAllOthers = false; 
                                break;
                            } 
                        } 

                        if (betterThanAllOthers) 
                        {
                            if (bestFunctionIndex == -1)
                            {
                                bestFunctionIndex = i; 
                            }
                            else 
                            { 
                                // Ambiguous.
                                return null; 
                            }
                        }
                    }
 
                    if (bestFunctionIndex == -1)
                    { 
                        return null; 
                    }
 
                    arguments = applicablePromotedArguments[bestFunctionIndex];
                    return applicableFunctions[bestFunctionIndex];
                }
            } 

            /// Rewrites an expression to propagate null values if necessary. 
            /// Expression to check for null. 
            /// Expression to yield if  does not yield null.
            /// The possibly rewriteen . 
            private Expression ConsiderNullPropagation(Expression element, Expression notNullExpression)
            {
                if (!this.nullPropagationRequired || element == this.it || !TypeAllowsNull(element.Type))
                { 
                    return notNullExpression;
                } 
 
                // Tiny optimization: remove the check on constants which are known not to be null.
                // Otherwise every string literal propagates out, which is correct but unnecessarily messy. 
                if (element is ConstantExpression && element != NullLiteral)
                {
                    return notNullExpression;
                } 

                // ifTrue and ifFalse expressions must match exactly. We need to ensure that the 'false' 
                // side is nullable, and the 'true' side is a null of the correct type. 
                Expression test = Expression.Equal(element, Expression.Constant(null, element.Type));
                Expression falseIf = notNullExpression; 
                if (!TypeAllowsNull(falseIf.Type))
                {
                    falseIf = Expression.Convert(falseIf, typeof(Nullable<>).MakeGenericType(falseIf.Type));
                } 

                Expression trueIf = Expression.Constant(null, falseIf.Type); 
                return Expression.Condition(test, trueIf, falseIf); 
            }
 
            /// Checks that the operand (possibly promoted) is valid for the specified operation.
            /// Type with signatures to match.
            /// Name of operation for error reporting.
            /// Expression for operand. 
            /// Position for error reporting.
            private void CheckAndPromoteOperand(Type signatures, string operationName, ref Expression expr, int errorPos) 
            { 
                Debug.Assert(signatures != null, "signatures != null");
                Debug.Assert(operationName != null, "operationName != null"); 
                Expression[] args = new Expression[] { expr };
                MethodBase method;
                if (this.FindMethod(signatures, "F", args, out method) != 1)
                { 
                    throw ParseError(Strings.RequestQueryParser_IncompatibleOperand(operationName, this.GetTypeName(args[0].Type), errorPos));
                } 
 
                expr = args[0];
            } 

            /// Checks that the operands (possibly promoted) are valid for the specified operation.
            /// Type with signatures to match.
            /// Name of operation for error reporting. 
            /// Expression for left operand.
            /// Expression for right operand. 
            /// Position for error reporting. 
            private void CheckAndPromoteOperands(Type signatures, string operationName, ref Expression left, ref Expression right, int errorPos)
            { 
                Expression[] args = new Expression[] { left, right };
                MethodBase method;
                if (this.FindMethod(signatures, "F", args, out method) != 1)
                { 
                    throw this.IncompatibleOperandsError(operationName, left, right, errorPos);
                } 
 
                left = args[0];
                right = args[1]; 
            }

            /// Finds a property in the specified type with the given name.
            /// Type in which to look for member. 
            /// Member name.
            /// The ResourceProperty for the specified type. 
            private ResourceProperty FindProperty(Type type, string memberName) 
            {
                // This could also be a FindPropertyOrField method. 
                Debug.Assert(type != null, "type != null");
                Debug.Assert(memberName != null, "memberName != null");

                ResourceProperty property = this.provider.TryResolvePropertyName(type, memberName); 
                if (property != null)
                { 
                    if (property.ResourceContainer != null) 
                    {
                        this.service.Configuration.CheckResourceRightsForRead(property.ResourceContainer, true /* singleResult */); 
                    }

                    return property;
                } 
                else
                { 
                    return null; 
                }
            } 

            /// Finds the named method in the specifid type.
            /// Type to look in.
            /// Name of method to look for. 
            /// Arguments to method.
            /// Best method found. 
            /// Number of matching methods. 
            private int FindMethod(Type type, string methodName, Expression[] args, out MethodBase method)
            { 
                BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance;
                foreach (Type t in SelfAndBaseTypes(type))
                {
                    MemberInfo[] members = t.FindMembers(MemberTypes.Method, flags, Type.FilterName, methodName); 
                    int count = this.FindBestMethod(members.Cast(), args, out method);
                    if (count != 0) 
                    { 
                        return count;
                    } 
                }

                method = null;
                return 0; 
            }
 
            /// Finds all applicable methods from the specified enumeration that match the arguments. 
            /// Enumerable object of candidate methods.
            /// Argument expressions. 
            /// Methods that apply to the specified arguments.
            private MethodData[] FindApplicableMethods(IEnumerable methods, Expression[] args)
            {
                List result = new List(); 
                foreach (MethodBase method in methods)
                { 
                    MethodData methodData = new MethodData(method, method.GetParameters()); 
                    if (this.IsApplicable(methodData, args))
                    { 
                        result.Add(methodData);
                    }
                }
 
                return result.ToArray();
            } 
 
            /// Finds the best methods for the specified arguments given a candidate method enumeration.
            /// Enumerable object for candidate methods. 
            /// Argument expressions to match.
            /// Best matched method.
            /// The number of "best match" methods.
            private int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method) 
            {
                MethodData[] applicable = this.FindApplicableMethods(methods, args); 
                if (applicable.Length > 1) 
                {
                    applicable = FindBestApplicableMethods(applicable, args); 
                }

                int result = applicable.Length;
                method = null; 
                if (applicable.Length == 1)
                { 
                    // If we started off with all non-OpenType expressions and end with all-OpenType 
                    // expressions, we've been too aggresive - the transition from non-open-types
                    // to open types should initially happen only as a result of accessing open properties. 
#if ASTORIA_OPEN_OBJECT
                    MethodData md = applicable[0];
                    bool originalArgsDefined = true;
                    bool promotedArgsOpen = true; 
                    for (int i = 0; i < args.Length; i++)
                    { 
                        originalArgsDefined = originalArgsDefined && !IsOpenPropertyExpression(args[i]); 
                        promotedArgsOpen = promotedArgsOpen && md.Parameters[i].ParameterType == typeof(object);
                        args[i] = md.Args[i]; 
                    }

                    method = (originalArgsDefined && promotedArgsOpen) ? null : md.MethodBase;
                    result = (method == null) ? 0 : 1; 
#else
                    for (int i = 0; i < args.Length; i++) 
                    { 
                        args[i] = applicable[0].Args[i];
                    } 

                    method = applicable[0].MethodBase;
                    result = 1;
#endif 
                }
                else if (applicable.Length > 1) 
                { 
                    // We may have the case for operators (which C# doesn't) in which we have a nullable operand
                    // and a non-nullable operand. We choose to convert the one non-null operand to nullable in that 
                    // case (the binary expression will lift to null).
                    if (args.Length == 2 && applicable.Length == 2 &&
                        GetNonNullableType(applicable[0].Parameters[0].ParameterType) ==
                        GetNonNullableType(applicable[1].Parameters[0].ParameterType)) 
                    {
                        MethodData nullableMethod = 
                            TypeAllowsNull(applicable[0].Parameters[0].ParameterType) ? 
                            applicable[0] :
                            applicable[1]; 
                        args[0] = nullableMethod.Args[0];
                        args[1] = nullableMethod.Args[1];
                        return this.FindBestMethod(methods, args, out method);
                    } 
                }
 
                return result; 
            }
 
            /// Gets a name that can be used for error messages.
            /// Type to get name for.
            /// The name of the specified .
            private string GetTypeName(Type type) 
            {
                Debug.Assert(type != null, "type != null"); 
                return WebUtil.GetTypeName(this.provider, type); 
            }
 
            /// Creates an exception indicated that two operands are incompatible.
            /// Name of operation for operands.
            /// Expression for left-hand operand.
            /// Expression for right-hand operand. 
            /// Position for error.
            /// A new . 
            private Exception IncompatibleOperandsError(string operationName, Expression left, Expression right, int pos) 
            {
                string message = Strings.RequestQueryParser_IncompatibleOperands( 
                    operationName,
                    this.GetTypeName(left.Type),
                    this.GetTypeName(right.Type),
                    pos); 
                return ParseError(message);
            } 
 
            /// Checks whether the specified method is applicable given the argument expressions.
            /// Method to check. 
            /// Argument expressions.
            /// true if the method is applicable; false otherwise.
            private bool IsApplicable(MethodData method, Expression[] args)
            { 
                if (method.Parameters.Length != args.Length)
                { 
                    return false; 
                }
 
                Expression[] promotedArgs = new Expression[args.Length];
                for (int i = 0; i < args.Length; i++)
                {
                    ParameterInfo pi = method.Parameters[i]; 
                    Debug.Assert(!pi.IsOut, "!pi.IsOut");
                    Expression promoted = this.PromoteExpression(args[i], pi.ParameterType, false); 
                    if (promoted == null) 
                    {
                        return false; 
                    }

                    promotedArgs[i] = promoted;
                } 

                method.Args = promotedArgs; 
                return true; 
            }
 
            /// Promotes the specified expression to the given type if necessary.
            /// Expression to promote.
            /// Type to change expression to.
            /// Whether an exact type is required; false implies a compatible type is OK. 
            /// Expression with the promoted type.
            private Expression PromoteExpression(Expression expr, Type type, bool exact) 
            { 
                Debug.Assert(expr != null, "expr != null");
                Debug.Assert(type != null, "type != null"); 
                if (expr.Type == type)
                {
                    return expr;
                } 

                ConstantExpression ce = expr as ConstantExpression; 
                if (ce != null) 
                {
                    if (ce == NullLiteral) 
                    {
                        if (TypeAllowsNull(type))
                        {
                            return Expression.Constant(null, type); 
                        }
                    } 
                    else 
                    {
                        string text; 
                        if (this.literals.TryGetValue(ce, out text))
                        {
                            Type target = GetNonNullableType(type);
                            object value = null; 
                            if (ce.Type == typeof(string) && target == typeof(Type))
                            { 
                                if (WebConvert.TryRemoveQuotes(ref text)) 
                                {
                                    ResourceType resourceType = this.provider.TryResolveTypeName(text); 
                                    if (resourceType != null)
                                    {
                                        value = resourceType.Type;
                                    } 
                                }
                            } 
                            else 
                            {
                                switch (Type.GetTypeCode(ce.Type)) 
                                {
                                    case TypeCode.Int32:
                                    case TypeCode.Int64:
                                        value = ParseNumber(text, target); 
                                        break;
                                    case TypeCode.Double: 
                                        if (target == typeof(decimal)) 
                                        {
                                            value = ParseNumber(text, target); 
                                        }

                                        break;
                                } 
                            }
 
                            if (value != null) 
                            {
                                return Expression.Constant(value, type); 
                            }
                        }
                    }
                } 

                if (IsCompatibleWith(expr.Type, type)) 
                { 
                    if (type.IsValueType || exact)
                    { 
                        return Expression.Convert(expr, type);
                    }

                    return expr; 
                }
 
                // Allow promotion from nullable to non-nullable by directly accessing underlying value. 
                if (IsNullableType(expr.Type) && type.IsValueType)
                { 
                    Expression valueAccessExpression = Expression.Property(expr, "Value");
                    valueAccessExpression = this.PromoteExpression(valueAccessExpression, type, exact);
                    return valueAccessExpression;
                } 

                return null; 
            } 

            /// Checks that the current token has the specified identifier. 
            /// Identifier to check.
            /// true if the current token is an identifier with the specified text.
            private bool TokenIdentifierIs(string id)
            { 
                return this.CurrentToken.IdentifierIs(id);
            } 
 
            /// Validates the current token is of the specified kind.
            /// Expected token kind. 
            private void ValidateToken(TokenId t)
            {
                if (this.CurrentToken.Id != t)
                { 
                    throw ParseError(Strings.RequestQueryParser_SyntaxError(this.CurrentToken.Position));
                } 
            } 

            #region Recursion control. 

            /// Marks the fact that a recursive method was entered, and checks that the depth is allowed.
            private void RecurseEnter()
            { 
                this.recursionDepth++;
                Debug.Assert(this.recursionDepth <= RecursionLimit, "this.recursionDepth <= recursionLimit"); 
                if (this.recursionDepth == RecursionLimit) 
                {
                    throw DataServiceException.CreateDeepRecursion(RecursionLimit); 
                }
            }

            /// Marks the fact that a recursive method is leaving.. 
            private void RecurseLeave()
            { 
                this.recursionDepth--; 
                Debug.Assert(0 <= this.recursionDepth, "0 <= this.recursionDepth");
                Debug.Assert(this.recursionDepth < RecursionLimit, "this.recursionDepth < recursionLimit"); 
            }

            #endregion Recursion control.
 
            /// Use this class to encapsulate method information.
            [DebuggerDisplay("MethodData {methodBase}")] 
            private class MethodData 
            {
                #region Private fields. 

                /// Described method.
                private readonly MethodBase methodBase;
 
                /// Parameters for method.
                private readonly ParameterInfo[] parameters; 
 
                /// Argument expressions.
                private Expression[] args; 

                #endregion Private fields.

                #region Constructors. 

                /// Initializes a new  instance. 
                /// Described method 
                /// Parameters for method.
                public MethodData(MethodBase method, ParameterInfo[] parameters) 
                {
                    this.methodBase = method;
                    this.parameters = parameters;
                } 

                #endregion Constructors. 
 
                #region Properties.
 
                /// Argument expressions.
                public Expression[] Args
                {
                    get { return this.args; } 
                    set { this.args = value; }
                } 
 
                /// Described method.
                public MethodBase MethodBase 
                {
                    get { return this.methodBase; }
                }
 
                /// Parameters for method.
                public ParameterInfo[] Parameters 
                { 
                    get { return this.parameters; }
                } 

                /// Enumeration of parameter types.
                public IEnumerable ParameterTypes
                { 
                    get
                    { 
                        foreach (ParameterInfo parameter in this.Parameters) 
                        {
                            yield return parameter.ParameterType; 
                        }
                    }
                }
 
                #endregion Properties.
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a type to parse expressions in request queries.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Parsing
{
    #region Namespaces. 

    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq; 
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Data.Services.Parsing;
    using System.Data.Services.Providers; 
#if ASTORIA_OPEN_OBJECT
    using System.Data.Services.OpenTypes; 
#endif 

    #endregion Namespaces. 

    /// 
    /// This class provides static methods to parse query options and compose
    /// them on an existing query. 
    /// 
    internal static class RequestQueryParser 
    { 
        #region Fields.
 
        /// Constant for "null" literal.
        internal static readonly ConstantExpression NullLiteral = Expression.Constant(null);

        #endregion Fields. 

        #region Internal methods. 
 
        /// Gets a type for  that allows null values.
        /// Type to base resulting type on. 
        /// 
        ///  if it's a reference or Nullable<> type;
        /// Nullable<> otherwise.
        ///  
        internal static Type GetTypeAllowingNull(Type type)
        { 
            Debug.Assert(type != null, "type != null"); 
            return TypeAllowsNull(type) ? type : typeof(Nullable<>).MakeGenericType(type);
        } 

        /// Checks whether the specified type is a generic nullable type.
        /// Type to check.
        /// true if  is nullable; false otherwise. 
        internal static bool IsNullableType(Type type)
        { 
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); 
        }
 
        /// Checks whether  is a null constant.
        /// Expression to check.
        /// true if  is a null constant; false otherwise.
        internal static bool IsNullConstant(Expression expression) 
        {
            Debug.Assert(expression != null, "expression != null"); 
            return 
                expression == NullLiteral ||
                (expression.NodeType == ExpressionType.Constant && ((ConstantExpression)expression).Value == null); 
        }

        /// Checks whether the specified  can be assigned null.
        /// Type to check. 
        /// true if type is a reference type or a Nullable type; false otherwise.
        internal static bool TypeAllowsNull(Type type) 
        { 
            Debug.Assert(type != null, "type != null");
            return !type.IsValueType || IsNullableType(type); 
        }

        /// Sorts a query like a SQL ORDER BY clause does.
        /// Service with data and configuration. 
        /// Original source for query.
        /// Ordering definition to compose. 
        /// The composed query. 
        internal static IQueryable OrderBy(IDataService service, IQueryable source, string ordering)
        { 
            Debug.Assert(service != null, "service != null");
            Debug.Assert(source != null, "source != null");
            Debug.Assert(ordering != null, "ordering != null");
 
            ParameterExpression parameterForIt = Expression.Parameter(source.ElementType, "it");
            ExpressionParser parser = new ExpressionParser(service, parameterForIt, ordering); 
            IEnumerable orderings = parser.ParseOrdering(); 
            Expression queryExpr = source.Expression;
            string methodAsc = "OrderBy"; 
            string methodDesc = "OrderByDescending";
            foreach (DynamicOrdering o in orderings)
            {
                Type selectorType = o.Selector.Type; 
                if (!service.Provider.GetTypeIsOrdered(selectorType))
                { 
                    string resourceTypeName = WebUtil.GetTypeName(service.Provider, o.Selector.Type); 
                    throw DataServiceException.CreateBadRequestError(Strings.RequestQueryParser_OrderByDoesNotSupportType(resourceTypeName));
                } 

                queryExpr = Expression.Call(
                    typeof(Queryable),
                    o.Ascending ? methodAsc : methodDesc, 
                    new Type[] { source.ElementType, selectorType },
                    queryExpr, 
                    Expression.Quote(Expression.Lambda(o.Selector, parameterForIt))); 
                methodAsc = "ThenBy";
                methodDesc = "ThenByDescending"; 
            }

            return source.Provider.CreateQuery(queryExpr);
        } 

        /// Filters a query like a SQL WHERE clause does. 
        /// Service with data and configuration. 
        /// Original source for query.
        /// Predicate to compose. 
        /// The composed query.
        internal static IQueryable Where(IDataService service, IQueryable source, string predicate)
        {
            Debug.Assert(service != null, "service != null"); 
            Debug.Assert(service != null, "source != null");
            Debug.Assert(predicate != null, "predicate != null"); 
 
            LambdaExpression lambda = ParseLambdaForWhere(service, source.ElementType, predicate);
            ////Trace.WriteLine("predicate=" + predicate + "; lambda=" + lambda.ToString()); 
            return source.Provider.CreateQuery(
                Expression.Call(typeof(Queryable), "Where", new Type[] { source.ElementType }, source.Expression, Expression.Quote(lambda)));
        }
 
        #endregion Internal methods.
 
        #region Private methods. 

        /// Parses a lambda expression. 
        /// Service with data and configuration.
        /// Type for "it" contextual variable.
        /// Expression to parse.
        /// The parsed expression. 
        private static LambdaExpression ParseLambdaForWhere(IDataService service, Type typeForIt, string expression)
        { 
            Debug.Assert(service != null, "service != null"); 
            Debug.Assert(typeForIt != null, "typeForIt != null");
            Debug.Assert(expression != null, "expression != null"); 
            ParameterExpression parameterForIt = Expression.Parameter(typeForIt, "it");
            ExpressionParser parser = new ExpressionParser(service, parameterForIt, expression);
            return Expression.Lambda(parser.ParseWhere(), parameterForIt);
        } 

        #endregion Private methods. 
 
        /// Use this class to define ordering for resources.
        private class DynamicOrdering 
        {
            #region Private fields.

            /// Whether the order is ascending. 
            private readonly bool ascending;
 
            /// Selector expression in ordering. 
            private readonly Expression selector;
 
            #endregion Private fields.

            /// Initializes a new  instance.
            /// Selector expression in ordering. 
            /// Whether the order is ascending.
            internal DynamicOrdering(Expression selector, bool ascending) 
            { 
                this.selector = selector;
                this.ascending = ascending; 
            }

            #region Properties.
 
            /// Whether the order is ascending.
            internal bool Ascending 
            { 
                get { return this.ascending; }
            } 

            /// Selector expression in ordering.
            internal Expression Selector
            { 
                get { return this.selector; }
            } 
 
            #endregion Properties.
        } 

        /// Use this class to parse an expression in the Astoria URI format.
        [DebuggerDisplay("ExpressionParser ({lexer.text})")]
        private class ExpressionParser 
        {
            #region Fields. 
 
            /// Maximum recursion limit on deserializer.
            private const int RecursionLimit = 100; 

            /// A type that is not numeric.
            private const int NumericTypeNotNumeric = 0;
 
            /// A type that is a char, single, double or decimal.
            private const int NumericTypeNotIntegral = 1; 
 
            /// A type that is a signed integral.
            private const int NumericTypeSignedIntegral = 2; 

            /// A type that is an unsigned integral.
            private const int NumericTypeUnsignedIntegral = 3;
 
            /// Empty Expressions array.
            private static readonly Expression[] emptyExpressions = new Expression[0]; 
 
            /// Constant for "true" literal.
            private static readonly ConstantExpression trueLiteral = Expression.Constant(true); 

            /// Constant for "false" literal.
            private static readonly ConstantExpression falseLiteral = Expression.Constant(false);
 
            /// Dictionary of system functions.
            private static readonly Dictionary functions = FunctionDescription.CreateFunctions(); 
 
            /// Provider of data and metadata.
            private readonly IDataServiceProvider provider; 

            /// Service with data and configuration.
            private readonly IDataService service;
 
            /// Literals.
            private Dictionary literals; 
 
            /// "it" contextual parameter.
            private ParameterExpression it; 

            /// Expression lexer.
            private ExpressionLexer lexer;
 
            /// Whether the expression tree should propagate nulls explicitly.
            private bool nullPropagationRequired; 
 
            /// Depth of recursion.
            private int recursionDepth; 

            #endregion Fields.

            #region Constructors. 

            /// Initializes a new . 
            /// Service with data and configuration. 
            /// Parameters for the current "it" context.
            /// Expression to parse. 
            internal ExpressionParser(IDataService service, ParameterExpression parameterForIt, string expression)
            {
                Debug.Assert(service != null, "service != null");
                Debug.Assert(expression != null, "expression != null"); 
                Debug.Assert(parameterForIt != null, "parameterForIt != null");
 
                this.service = service; 
                this.provider = service.Provider;
                this.nullPropagationRequired = this.provider.NullPropagationRequired; 
                this.literals = new Dictionary();
                this.it = parameterForIt;
                this.lexer = new ExpressionLexer(expression);
            } 

            #endregion Constructors. 
 
            /// Current token being processed.
            private Token CurrentToken 
            {
                get { return this.lexer.CurrentToken; }
                set { this.lexer.CurrentToken = value; }
            } 

            /// Parses the text expression for a .Where method invocation. 
            /// The parsed expression. 
            internal Expression ParseWhere()
            { 
                int exprPos = this.lexer.Position;
                Expression expr = this.ParseExpression();
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(expr)) 
                {
                    expr = Expression.Convert(expr, typeof(bool)); 
                } 
                else
#endif 
                    if (IsNullConstant(expr))
                {
                    expr = falseLiteral;
                } 
                else if (expr.Type == typeof(bool?))
                { 
                    Expression test = Expression.Equal(expr, Expression.Constant(null, typeof(bool?))); 
                    expr = Expression.Condition(test, falseLiteral, Expression.Property(expr, "Value"));
                } 
                else if (expr.Type != typeof(bool))
                {
                    throw ParseError(Strings.RequestQueryParser_ExpressionTypeMismatch(this.GetTypeName(typeof(bool)), exprPos));
                } 

                this.lexer.ValidateToken(TokenId.End); 
                Debug.Assert(expr != null, "expr != null"); 
                Debug.Assert(expr.Type == typeof(bool), "expr.Type(" + expr.Type + ") == typeof(bool)");
                return expr; 
            }

            /// Parses the text expression for ordering.
            /// An enumeration of orderings. 
            internal IEnumerable ParseOrdering()
            { 
                List orderings = new List(); 
                while (true)
                { 
                    Expression expr = this.ParseExpression();
                    bool ascending = true;
                    if (this.TokenIdentifierIs(ExpressionConstants.KeywordAscending))
                    { 
                        this.lexer.NextToken();
                    } 
                    else if (this.TokenIdentifierIs(ExpressionConstants.KeywordDescending)) 
                    {
                        this.lexer.NextToken(); 
                        ascending = false;
                    }

                    orderings.Add(new DynamicOrdering(expr, ascending)); 
                    if (this.CurrentToken.Id != TokenId.Comma)
                    { 
                        break; 
                    }
 
                    this.lexer.NextToken();
                }

                this.ValidateToken(TokenId.End); 
                return orderings;
            } 
 
            /// Compares two byte arrays for equality.
            /// First byte array.Second byte array. 
            /// true if the arrays are equal; false otherwise.
            private static bool ByteArraysEqual(byte[] b0, byte[] b1)
            {
                if (b0 == b1) 
                {
                    return true; 
                } 

                if (b0 == null || b1 == null) 
                {
                    return false;
                }
 
                if (b0.Length != b1.Length)
                { 
                    return false; 
                }
 
                for (int i = 0; i < b0.Length; i++)
                {
                    if (b0[i] != b1[i])
                    { 
                        return false;
                    } 
                } 

                return true; 
            }

            /// Compares two byte arrays for equality.
            /// First byte array.Second byte array. 
            /// true if the arrays are not equal; false otherwise.
            private static bool ByteArraysNotEqual(byte[] b0, byte[] b1) 
            { 
                return !ByteArraysEqual(b0, b1);
            } 

            /// Gets a non-nullable version of the specified type.
            /// Type to get non-nullable version for.
            ///  
            ///  if type is a reference type or a
            /// non-nullable type; otherwise, the underlying value type. 
            ///  
            private static Type GetNonNullableType(Type type)
            { 
                return Nullable.GetUnderlyingType(type) ?? type;
            }

            /// Checks whether the specified type is a signed integral type. 
            /// Type to check.
            /// true if  is a signed integral type; false otherwise. 
            private static bool IsSignedIntegralType(Type type) 
            {
                return GetNumericTypeKind(type) == NumericTypeSignedIntegral; 
            }

            /// Checks whether the specified type is an unsigned integral type.
            /// Type to check. 
            /// true if  is an unsigned integral type; false otherwise.
            private static bool IsUnsignedIntegralType(Type type) 
            { 
                return GetNumericTypeKind(type) == NumericTypeUnsignedIntegral;
            } 

            /// Gets a flag for the numeric kind of type.
            /// Type to get numeric kind for.
            ///  
            /// One of NumericTypeNotNumeric; NumericTypeNotIntegral if it's char,
            /// single, double or decimal; NumericTypeSignedIntegral, or NumericTypeUnsignedIntegral. 
            ///  
            private static int GetNumericTypeKind(Type type)
            { 
                type = GetNonNullableType(type);
                Debug.Assert(!type.IsEnum, "!type.IsEnum");
                switch (Type.GetTypeCode(type))
                { 
                    case TypeCode.Char:
                    case TypeCode.Single: 
                    case TypeCode.Double: 
                    case TypeCode.Decimal:
                        return NumericTypeNotIntegral; 
                    case TypeCode.SByte:
                    case TypeCode.Int16:
                    case TypeCode.Int32:
                    case TypeCode.Int64: 
                        return NumericTypeSignedIntegral;
                    case TypeCode.Byte: 
                        return NumericTypeUnsignedIntegral; 
                    default:
                        return NumericTypeNotNumeric; 
                }
            }

            /// Checks whether type is a (possibly nullable) enumeration type. 
            /// Type to check.
            /// true if type is an enumeration or a nullable enumeration; false otherwise. 
            private static bool IsEnumType(Type type) 
            {
                return GetNonNullableType(type).IsEnum; 
            }

            /// Returns an object that can enumerate the specified type and its supertypes.
            /// Type to based enumeration on. 
            /// An object that can enumerate the specified type and its supertypes.
            private static IEnumerable SelfAndBaseTypes(Type type) 
            { 
                if (type.IsInterface)
                { 
                    List types = new List();
                    AddInterface(types, type);
                    return types;
                } 

                return SelfAndBaseClasses(type); 
            } 

            /// Returns an object that can enumerate the specified type and its supertypes. 
            /// Type to based enumeration on.
            /// An object that can enumerate the specified type and its supertypes.
            private static IEnumerable SelfAndBaseClasses(Type type)
            { 
                while (type != null)
                { 
                    yield return type; 
                    type = type.BaseType;
                } 
            }

            /// Adds an interface type to a list of types, including inherited interfaces.
            /// Types list ot add to. 
            /// Interface type to add.
            private static void AddInterface(List types, Type type) 
            { 
                if (!types.Contains(type))
                { 
                    types.Add(type);
                    foreach (Type t in type.GetInterfaces())
                    {
                        AddInterface(types, t); 
                    }
                } 
            } 

            /// Finds the best applicable methods from the specified array that match the arguments. 
            /// Candidate methods.
            /// Argument expressions.
            /// Best applicable methods.
            private static MethodData[] FindBestApplicableMethods(MethodData[] applicable, Expression[] args) 
            {
                Debug.Assert(applicable != null, "applicable != null"); 
 
                List result = new List();
                foreach (MethodData method in applicable) 
                {
                    bool betterThanAllOthers = true;
                    foreach (MethodData otherMethod in applicable)
                    { 
                        if (otherMethod != method && IsBetterThan(args, otherMethod, method))
                        { 
                            betterThanAllOthers = false; 
                            break;
                        } 
                    }

                    if (betterThanAllOthers)
                    { 
                        result.Add(method);
                    } 
                } 

                return result.ToArray(); 
            }

            /// Parses the specified text into a number.
            /// Text to parse. 
            /// Type to parse into.
            /// The parsed number. 
            private static object ParseNumber(string text, Type type) 
            {
                TypeCode tc = Type.GetTypeCode(GetNonNullableType(type)); 
                switch (tc)
                {
                    case TypeCode.SByte:
                        sbyte sb; 
                        if (sbyte.TryParse(text, out sb))
                        { 
                            return sb; 
                        }
 
                        break;
                    case TypeCode.Byte:
                        byte b;
                        if (byte.TryParse(text, out b)) 
                        {
                            return b; 
                        } 

                        break; 
                    case TypeCode.Int16:
                        short s;
                        if (short.TryParse(text, out s))
                        { 
                            return s;
                        } 
 
                        break;
                    case TypeCode.Int32: 
                        int i;
                        if (int.TryParse(text, out i))
                        {
                            return i; 
                        }
 
                        break; 
                    case TypeCode.Int64:
                        long l; 
                        if (long.TryParse(text, out l))
                        {
                            return l;
                        } 

                        break; 
                    case TypeCode.Single: 
                        float f;
                        if (float.TryParse(text, out f)) 
                        {
                            return f;
                        }
 
                        break;
                    case TypeCode.Double: 
                        double d; 
                        if (double.TryParse(text, out d))
                        { 
                            return d;
                        }

                        break; 
                    case TypeCode.Decimal:
                        decimal e; 
                        if (decimal.TryParse(text, out e)) 
                        {
                            return e; 
                        }

                        break;
                } 

                return null; 
            } 

            /// Checks whether the source type is compatible with the value type. 
            /// Source type.
            /// Target type.
            /// true if source can be used in place of target; false otherwise.
            private static bool IsCompatibleWith(Type source, Type target) 
            {
                if (source == target) 
                { 
                    return true;
                } 

                if (!target.IsValueType)
                {
                    return target.IsAssignableFrom(source); 
                }
 
                Type sourceType = GetNonNullableType(source); 
                Type targetType = GetNonNullableType(target);
 
                //// This rule stops the parser from considering nullable types as incompatible
                //// with non-nullable types. We have however implemented this rule because we just
                //// access underlying rules. C# requires an explicit .Value access, and EDM has no
                //// nullablity on types and (at the model level) implements null propagation. 
                ////
                //// if (sourceType != source && targetType == target) 
                //// { 
                ////     return false;
                //// } 

                TypeCode sourceCode = sourceType.IsEnum ? TypeCode.Object : Type.GetTypeCode(sourceType);
                TypeCode targetCode = targetType.IsEnum ? TypeCode.Object : Type.GetTypeCode(targetType);
                switch (sourceCode) 
                {
                    case TypeCode.SByte: 
                        switch (targetCode) 
                        {
                            case TypeCode.SByte: 
                            case TypeCode.Int16:
                            case TypeCode.Int32:
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true; 
                        }
 
                        break;
                    case TypeCode.Byte:
                        switch (targetCode)
                        { 
                            case TypeCode.Byte:
                            case TypeCode.Int16: 
                            case TypeCode.Int32: 
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                                return true;
                        } 

                        break; 
                    case TypeCode.Int16: 
                        switch (targetCode)
                        { 
                            case TypeCode.Int16:
                            case TypeCode.Int32:
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true; 
                        }
 
                        break;
                    case TypeCode.Int32:
                        switch (targetCode)
                        { 
                            case TypeCode.Int32:
                            case TypeCode.Int64: 
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal: 
                                return true;
                        }

                        break; 
                    case TypeCode.Int64:
                        switch (targetCode) 
                        { 
                            case TypeCode.Int64:
                            case TypeCode.Single: 
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                                return true;
                        } 

                        break; 
                    case TypeCode.Single: 
                        switch (targetCode)
                        { 
                            case TypeCode.Single:
                            case TypeCode.Double:
                                return true;
                        } 

                        break; 
                    default: 
                        if (sourceType == targetType)
                        { 
                            return true;
                        }

                        break; 
                }
 
                // Anything can be converted to something that's *exactly* an object. 
#if ASTORIA_OPEN_OBJECT
                if (target == typeof(object)) 
                {
                    return true;
                }
#endif 

                return false; 
            } 

            ///  
            /// Checks whether one type list is a better fit than other for the
            /// specified expressions.
            /// 
            /// Expressions for arguments. 
            /// First type list to check.
            /// Second type list to check. 
            ///  
            /// true if  has better parameter matching than .
            ///  
            private static bool IsBetterThan(Expression[] args, IEnumerable firstCandidate, IEnumerable secondCandidate)
            {
                bool better = false;
 
                using (IEnumerator first = firstCandidate.GetEnumerator())
                using (IEnumerator second = secondCandidate.GetEnumerator()) 
                { 
                    for (int i = 0; i < args.Length; i++)
                    { 
                        first.MoveNext();
                        second.MoveNext();
                        int c = CompareConversions(args[i].Type, first.Current, second.Current);
                        if (c < 0) 
                        {
                            return false; 
                        } 
                        else if (c > 0)
                        { 
                            better = true;
                        }
                    }
                } 

                return better; 
            } 

            ///  
            /// Checks whether one method is a better fit than other for the
            /// specified expressions.
            /// 
            /// Expressions for arguments. 
            /// First method to check.
            /// Second method to check. 
            ///  
            /// true if  has better parameter matching than .
            ///  
            private static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
            {
                Debug.Assert(args != null, "args != null");
                Debug.Assert(m1 != null, "m1 != null"); 
                Debug.Assert(m2 != null, "m2 != null");
                return IsBetterThan(args, m1.ParameterTypes, m2.ParameterTypes); 
            } 

            /// Checks which conversion is better. 
            /// Source type.
            /// First candidate type to convert to.
            /// Second candidate type to convert to.
            ///  
            /// Return 1 if s -> t1 is a better conversion than s -> t2
            /// Return -1 if s -> t2 is a better conversion than s -> t1 
            /// Return 0 if neither conversion is better 
            /// 
            private static int CompareConversions(Type source, Type targetA, Type targetB) 
            {
                // If both types are exactly the same, there is no preference.
                if (targetA == targetB)
                { 
                    return 0;
                } 
 
                // Look for exact matches.
                if (source == targetA) 
                {
                    return 1;
                }
                else if (source == targetB) 
                {
                    return -1; 
                } 

                // If one is compatible and the other is not, choose the compatible type. 
                bool compatibleT1AndT2 = IsCompatibleWith(targetA, targetB);
                bool compatibleT2AndT1 = IsCompatibleWith(targetB, targetA);
                if (compatibleT1AndT2 && !compatibleT2AndT1)
                { 
                    return 1;
                } 
                else if (compatibleT2AndT1 && !compatibleT1AndT2) 
                {
                    return -1; 
                }

                // Prefer to keep the original nullability.
                bool sourceNullable = IsNullableType(source); 
                bool typeNullableA = IsNullableType(targetA);
                bool typeNullableB = IsNullableType(targetB); 
                if (sourceNullable == typeNullableA && sourceNullable != typeNullableB) 
                {
                    return 1; 
                }
                else if (sourceNullable != typeNullableA && sourceNullable == typeNullableB)
                {
                    return -1; 
                }
 
                // Prefer signed to unsigned. 
                if (IsSignedIntegralType(targetA) && IsUnsignedIntegralType(targetB))
                { 
                    return 1;
                }
                else if (IsSignedIntegralType(targetB) && IsUnsignedIntegralType(targetA))
                { 
                    return -1;
                } 
 
                // Prefer non-object to object.
                if (targetA != typeof(object) && targetB == typeof(object)) 
                {
                    return 1;
                }
                else if (targetB != typeof(object) && targetA == typeof(object)) 
                {
                    return -1; 
                } 

                return 0; 
            }

            /// Generates an Equal expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression. 
            private static Expression GenerateEqual(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                {
                    return LateBoundMethods.EqualExpression(left, right);
                } 
#endif
 
                if (left.Type == typeof(byte[])) 
                {
                    MethodInfo byteArrayCompareMethod = typeof(ExpressionParser).GetMethod("ByteArraysEqual", BindingFlags.NonPublic | BindingFlags.Static); 
                    return Expression.Equal(left, right, false, byteArrayCompareMethod);
                }

                return Expression.Equal(left, right); 
            }
 
            /// Generates a NotEqual expression. 
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateNotEqual(Expression left, Expression right)
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.NotEqualExpression(left, right); 
                }
#endif 

                if (left.Type == typeof(byte[]))
                {
                    MethodInfo byteArrayCompareMethod = typeof(ExpressionParser).GetMethod("ByteArraysNotEqual", BindingFlags.NonPublic | BindingFlags.Static); 
                    return Expression.NotEqual(left, right, false, byteArrayCompareMethod);
                } 
 
                return Expression.NotEqual(left, right);
            } 

            /// Generates a GreaterThan comparison expression.
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateGreaterThan(Expression left, Expression right) 
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                {
                    return LateBoundMethods.GreaterThanExpression(left, right);
                }
#endif 

                if (left.Type == typeof(string)) 
                { 
                    return Expression.GreaterThan(left, right, false, GetStringCompareMethod("StringGreaterThanMethod"));
                } 

                return Expression.GreaterThan(left, right);
            }
 
            /// Generates a GreaterThanOrEqual comparsion expression.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateGreaterThanEqual(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.GreaterThanOrEqualExpression(left, right);
                } 
#endif 

                if (left.Type == typeof(string)) 
                {
                    return Expression.GreaterThanOrEqual(left, right, false, GetStringCompareMethod("StringGreaterThanOrEqualMethod"));
                }
 
                return Expression.GreaterThanOrEqual(left, right);
            } 
 
            /// Generates a LessThan comparsion expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression.
            private static Expression GenerateLessThan(Expression left, Expression right)
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                { 
                    return LateBoundMethods.LessThanExpression(left, right);
                } 
#endif

                if (left.Type == typeof(string))
                { 
                    return Expression.LessThan(left, right, false, GetStringCompareMethod("StringLessThanMethod"));
                } 
 
                return Expression.LessThan(left, right);
            } 

            /// Generates a LessThanOrEqual comparsion expression.
            /// Left expression.
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateLessThanEqual(Expression left, Expression right) 
            { 
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right)) 
                {
                    return LateBoundMethods.LessThanOrEqualExpression(left, right);
                }
#endif 

                if (left.Type == typeof(string)) 
                { 
                    return Expression.LessThanOrEqual(left, right, false, GetStringCompareMethod("StringLessThanOrEqualMethod"));
                } 

                return Expression.LessThanOrEqual(left, right);
            }
 
            /// Generates an addition expression.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateAdd(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                { 
                    return LateBoundMethods.AddExpression(left, right);
                } 
#endif 

                return Expression.Add(left, right); 
            }

            /// Generates a subtract expression.
            /// Left expression. 
            /// Right expression.
            /// The generated expression. 
            private static Expression GenerateSubtract(Expression left, Expression right) 
            {
#if ASTORIA_OPEN_OBJECT 
                if (IsOpenPropertyExpression(left) || IsOpenPropertyExpression(right))
                {
                    return LateBoundMethods.SubtractExpression(left, right);
                } 
#endif
 
                return Expression.Subtract(left, right); 
            }
 
            /// Gets a static method to compare strings.
            /// Name of method.
            /// The  for the method.
            private static MethodInfo GetStringCompareMethod(string methodName) 
            {
                Debug.Assert(methodName != null, "methodName != null"); 
                MethodInfo result = typeof(ExpressionParser).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static); 
                Debug.Assert(result != null, "result != null");
                return result; 
            }

#if ASTORIA_OPEN_OBJECT
            ///  
            /// Checks whether the specified  is part of an open property expression.
            ///  
            /// Non-null  to check. 
            /// true if  is based on an open property; false otherwise.
            private static bool IsOpenPropertyExpression(Expression expression) 
            {
                Debug.Assert(expression != null, "expression != null");
                return expression != NullLiteral && expression.Type == typeof(object);
            } 
#endif
 
            /// Checks whether the left string is less than or equal to the right string. 
            /// Left value.Right value.
            /// true if the left string is less than or equal to the right string. 
            private static bool StringLessThanOrEqualMethod(string left, string right)
            {
                return string.CompareOrdinal(left, right) <= 0;
            } 

            /// Checks whether the left string is less than the right string. 
            /// Left value.Right value. 
            /// true if the left string is less than the right string.
            private static bool StringLessThanMethod(string left, string right) 
            {
                return string.CompareOrdinal(left, right) < 0;
            }
 
            /// Checks whether the left string is greater than or equal to the right string.
            /// Left value.Right value. 
            /// true if the left string is greater than or equal to the right string. 
            private static bool StringGreaterThanOrEqualMethod(string left, string right)
            { 
                return string.CompareOrdinal(left, right) >= 0;
            }

            /// Checks whether the left string is greater than the right string. 
            /// Left value.Right value.
            /// true if the left string is greater than the right string. 
            private static bool StringGreaterThanMethod(string left, string right) 
            {
                return string.CompareOrdinal(left, right) > 0; 
            }

            /// Gets a static method by name.
            /// Name of method to get. 
            /// Left expression to resolve method from and to use as argument.
            /// Right expression. 
            /// The method. 
            private static MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
            { 
                return left.Type.GetMethod(methodName, new Type[] { left.Type, right.Type });
            }

            /// Generates a static method call. 
            /// Method name.
            /// Left expression. 
            /// Right expression. 
            /// The generated expression.
            private static Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) 
            {
                return Expression.Call(null, GetStaticMethod(methodName, left, right), new Expression[] { left, right });
            }
 
            /// Creates an exception for a parse error.
            /// Message text. 
            /// A new Exception. 
            private static Exception ParseError(string message)
            { 
                return DataServiceException.CreateSyntaxError(message);
            }

            /// Checks that the given token has the specified identifier. 
            /// Token to check
            /// Identifier to check. 
            /// true if  is an identifier with the specified text. 
            private static bool TokenIdentifierIs(Token token, string id)
            { 
                return token.Id == TokenId.Identifier && String.Equals(id, token.Text, StringComparison.OrdinalIgnoreCase);
            }

            #region Parsing. 

            /// Handles a ?: operator - not supported. 
            /// The parsed expression. 
            private Expression ParseExpression()
            { 
                this.RecurseEnter();
                Expression expr = this.ParseLogicalOr();
                this.RecurseLeave();
                return expr; 
            }
 
            /// Handles or operator. 
            /// The parsed expression.
            private Expression ParseLogicalOr() 
            {
                this.RecurseEnter();
                Expression left = this.ParseLogicalAnd();
                while (this.TokenIdentifierIs(ExpressionConstants.KeywordOr)) 
                {
                    Token op = this.CurrentToken; 
                    this.lexer.NextToken(); 
                    Expression right = this.ParseLogicalAnd();
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.ILogicalSignatures), op.Text, ref left, ref right, op.Position); 
#if ASTORIA_OPEN_OBJECT
                    if (left.Type == typeof(object) || right.Type == typeof(object))
                    {
                        left = LateBoundMethods.OrElseExpression(left, right); 
                        if (left == null)
                        { 
                            throw ParseError(Strings.RequestQueryParser_BooleanExpressionsExpectedFor(op.Text)); 
                        }
                    } 
                    else
#endif
                    {
                        left = Expression.OrElse(left, right); 
                    }
                } 
 
                this.RecurseLeave();
                return left; 
            }

            /// Handles and operator.
            /// The parsed expression. 
            private Expression ParseLogicalAnd()
            { 
                this.RecurseEnter(); 
                Expression left = this.ParseComparison();
                while (this.TokenIdentifierIs(ExpressionConstants.KeywordAnd)) 
                {
                    Token op = this.CurrentToken;
                    this.lexer.NextToken();
                    Expression right = this.ParseComparison(); 
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.ILogicalSignatures), op.Text, ref left, ref right, op.Position);
#if ASTORIA_OPEN_OBJECT 
                    if (left.Type == typeof(object) || right.Type == typeof(object)) 
                    {
                        left = LateBoundMethods.AndAlsoExpression(left, right); 
                        if (left == null)
                        {
                            throw ParseError(Strings.RequestQueryParser_BooleanExpressionsExpectedFor(op.Text));
                        } 
                    }
                    else 
#endif 
                    {
                        left = Expression.AndAlso(left, right); 
                    }
                }

                this.RecurseLeave(); 
                return left;
            } 
 
            /// Handles eq, ne, lt, gt, le, ge operators.
            /// The parsed expression. 
            private Expression ParseComparison()
            {
                this.RecurseEnter();
                Expression left = this.ParseAdditive(); 
                while (this.CurrentToken.IsComparisonOperator)
                { 
                    Token op = this.CurrentToken; 
                    this.lexer.NextToken();
                    Expression right = this.ParseAdditive(); 
                    bool equality = op.IsEqualityOperator;

                    if (equality && !left.Type.IsValueType && !right.Type.IsValueType)
                    { 
                        if (left.Type != right.Type)
                        { 
                            if (IsNullConstant(left)) 
                            {
                                left = Expression.Constant(null, right.Type); 
                            }
                            else if (IsNullConstant(right))
                            {
                                right = Expression.Constant(null, left.Type); 
                            }
                            else if (left.Type.IsAssignableFrom(right.Type)) 
                            { 
                                right = Expression.Convert(right, left.Type);
                            } 
                            else if (right.Type.IsAssignableFrom(left.Type))
                            {
                                left = Expression.Convert(left, right.Type);
                            } 
                            else
                            { 
                                throw this.IncompatibleOperandsError(op.Text, left, right, op.Position); 
                            }
                        } 
                    }
                    else if (left == NullLiteral || right == NullLiteral)
                    {
                        if (!equality) 
                        {
                            throw ParseError( 
                                Strings.RequestQueryParser_NullOperatorUnsupported(op.Text, op.Position, this.lexer.ExpressionText)); 
                        }
 
                        // Because we don't have an explicit "is null" check, literal comparisons
                        // to null are special.
                        if (!TypeAllowsNull(left.Type))
                        { 
                            left = Expression.Convert(left, typeof(Nullable<>).MakeGenericType(left.Type));
                        } 
                        else if (!TypeAllowsNull(right.Type)) 
                        {
                            right = Expression.Convert(right, typeof(Nullable<>).MakeGenericType(right.Type)); 
                        }
                    }
                    else
                    { 
                        // Enums should be checked here for promotion when supported, but they aren't in this version.
                        Debug.Assert(!IsEnumType(left.Type), "!IsEnumType(left.Type)"); 
                        Debug.Assert(!IsEnumType(right.Type), "!IsEnumType(right.Type)"); 

                        Type signatures = equality ? typeof(OperationSignatures.IEqualitySignatures) : typeof(OperationSignatures.IRelationalSignatures); 
                        this.CheckAndPromoteOperands(signatures, op.Text, ref left, ref right, op.Position);
                    }

                    Debug.Assert(op.Id == TokenId.Identifier, "op.id == TokenId.Identifier"); 
                    switch (op.Text)
                    { 
                        case ExpressionConstants.KeywordEqual: 
                            left = GenerateEqual(left, right);
                            break; 
                        case ExpressionConstants.KeywordNotEqual:
                            left = GenerateNotEqual(left, right);
                            break;
                        case ExpressionConstants.KeywordGreaterThan: 
                            left = GenerateGreaterThan(left, right);
                            break; 
                        case ExpressionConstants.KeywordGreaterThanOrEqual: 
                            left = GenerateGreaterThanEqual(left, right);
                            break; 
                        case ExpressionConstants.KeywordLessThan:
                            left = GenerateLessThan(left, right);
                            break;
                        case ExpressionConstants.KeywordLessThanOrEqual: 
                            left = GenerateLessThanEqual(left, right);
                            break; 
                    } 
                }
 
                this.RecurseLeave();
                return left;
            }
 
            /// Handles +, -, & operators (& for string concat, not supported).
            /// The parsed expression. 
            private Expression ParseAdditive() 
            {
                this.RecurseEnter(); 
                Expression left = this.ParseMultiplicative();
                while (this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordAdd) ||
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordSub))
                { 
                    Token op = this.CurrentToken;
                    this.lexer.NextToken(); 
                    Expression right = this.ParseMultiplicative(); 
                    if (op.IdentifierIs(ExpressionConstants.KeywordAdd))
                    { 
                        this.CheckAndPromoteOperands(typeof(OperationSignatures.IAddSignatures), op.Text, ref left, ref right, op.Position);
                        left = GenerateAdd(left, right);
                    }
                    else 
                    {
                        Debug.Assert(ExpressionParser.TokenIdentifierIs(op, ExpressionConstants.KeywordSub), "ExpressionParser.TokenIdentifierIs(op, ExpressionConstants.KeywordSub)"); 
                        this.CheckAndPromoteOperands(typeof(OperationSignatures.ISubtractSignatures), op.Text, ref left, ref right, op.Position); 
                        left = GenerateSubtract(left, right);
                    } 
                }

                this.RecurseLeave();
                return left; 
            }
 
            /// Handles mul, div, mod operators. 
            /// The parsed expression.
            private Expression ParseMultiplicative() 
            {
                this.RecurseEnter();
                Expression left = this.ParseUnary();
                while (this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordMultiply) || 
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordDivide) ||
                    this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordModulo)) 
                { 
                    Token op = this.CurrentToken;
                    this.lexer.NextToken(); 
                    Expression right = this.ParseUnary();
                    this.CheckAndPromoteOperands(typeof(OperationSignatures.IArithmeticSignatures), op.Text, ref left, ref right, op.Position);
                    if (op.IdentifierIs(ExpressionConstants.KeywordMultiply))
                    { 
#if ASTORIA_OPEN_OBJECT
                        if (left.Type == typeof(object) || right.Type == typeof(object)) 
                        { 
                            left = LateBoundMethods.MultiplyExpression(left, right);
                        } 
                        else
#endif
                        {
                            left = Expression.Multiply(left, right); 
                        }
                    } 
                    else if (op.IdentifierIs(ExpressionConstants.KeywordDivide)) 
                    {
#if ASTORIA_OPEN_OBJECT 
                        if (left.Type == typeof(object) || right.Type == typeof(object))
                        {
                            left = LateBoundMethods.DivideExpression(left, right);
                        } 
                        else
#endif 
                        { 
                            left = Expression.Divide(left, right);
                        } 
                    }
                    else
                    {
                        Debug.Assert(op.IdentifierIs(ExpressionConstants.KeywordModulo), "op.IdentifierIs(ExpressionConstants.KeywordModulo)"); 
#if ASTORIA_OPEN_OBJECT
                        if (left.Type == typeof(object) || right.Type == typeof(object)) 
                        { 
                            left = LateBoundMethods.ModuloExpression(left, right);
                        } 
                        else
#endif
                        {
                            left = Expression.Modulo(left, right); 
                        }
                    } 
                } 

                this.RecurseLeave(); 
                return left;
            }

            /// Handles -, not unary operators. 
            /// The parsed expression.
            private Expression ParseUnary() 
            { 
                this.RecurseEnter();
                if (this.CurrentToken.Id == TokenId.Minus || this.CurrentToken.IdentifierIs(ExpressionConstants.KeywordNot)) 
                {
                    Token op = this.CurrentToken;
                    this.lexer.NextToken();
                    if (op.Id == TokenId.Minus && (ExpressionLexer.IsNumeric(this.CurrentToken.Id))) 
                    {
                        Token numberLiteral = this.CurrentToken; 
                        numberLiteral.Text = "-" + numberLiteral.Text; 
                        numberLiteral.Position = op.Position;
                        this.CurrentToken = numberLiteral; 
                        this.RecurseLeave();
                        return this.ParsePrimary();
                    }
 
                    Expression expr = this.ParseUnary();
                    if (op.Id == TokenId.Minus) 
                    { 
                        this.CheckAndPromoteOperand(typeof(OperationSignatures.INegationSignatures), op.Text, ref expr, op.Position);
#if ASTORIA_OPEN_OBJECT 
                        if (expr.Type == typeof(object))
                        {
                            expr = LateBoundMethods.NegateExpression(expr);
                        } 
                        else
#endif 
                        { 
                            expr = Expression.Negate(expr);
                        } 
                    }
                    else
                    {
                        this.CheckAndPromoteOperand(typeof(OperationSignatures.INotSignatures), op.Text, ref expr, op.Position); 
#if ASTORIA_OPEN_OBJECT
                        if (expr.Type == typeof(object)) 
                        { 
                            expr = LateBoundMethods.NotExpression(expr);
                        } 
                        else
#endif
                        if (expr.Type == typeof(bool) || expr.Type == typeof(Nullable))
                        { 
                            // Expression.Not will take numerics and apply '~' to them, thus the extra check here.
                            expr = Expression.Not(expr); 
                        } 
                        else
                        { 
                            throw ParseError(Strings.RequestQueryParser_NotDoesNotSupportType(expr.Type));
                        }
                    }
 
                    this.RecurseLeave();
                    return expr; 
                } 

                this.RecurseLeave(); 
                return this.ParsePrimary();
            }

            /// Handles primary expressions. 
            /// The parsed expression.
            private Expression ParsePrimary() 
            { 
                this.RecurseEnter();
                Expression expr = this.ParsePrimaryStart(); 
                while (true)
                {
                    if (this.CurrentToken.Id == TokenId.Slash)
                    { 
                        this.lexer.NextToken();
                        expr = this.ParseMemberAccess(expr); 
                    } 
                    else
                    { 
                        break;
                    }
                }
 
                this.RecurseLeave();
                return expr; 
            } 

            /// Handles the start of primary expressions. 
            /// The parsed expression.
            private Expression ParsePrimaryStart()
            {
                switch (this.CurrentToken.Id) 
                {
                    case TokenId.BooleanLiteral: 
                        return this.ParseTypedLiteral(typeof(bool), XmlConstants.EdmBooleanTypeName); 
                    case TokenId.DateTimeLiteral:
                        return this.ParseTypedLiteral(typeof(DateTime), XmlConstants.EdmDateTimeTypeName); 
                    case TokenId.DecimalLiteral:
                        return this.ParseTypedLiteral(typeof(decimal), XmlConstants.EdmDecimalTypeName);
                    case TokenId.NullLiteral:
                        return this.ParseNullLiteral(); 
                    case TokenId.Identifier:
                        return this.ParseIdentifier(); 
                    case TokenId.StringLiteral: 
                        return this.ParseTypedLiteral(typeof(string), XmlConstants.EdmStringTypeName);
                    case TokenId.Int64Literal: 
                        return this.ParseTypedLiteral(typeof(Int64), XmlConstants.EdmInt64TypeName);
                    case TokenId.IntegerLiteral:
                        return this.ParseTypedLiteral(typeof(Int32), XmlConstants.EdmInt32TypeName);
                    case TokenId.DoubleLiteral: 
                        return this.ParseTypedLiteral(typeof(double), XmlConstants.EdmDoubleTypeName);
                    case TokenId.SingleLiteral: 
                        return this.ParseTypedLiteral(typeof(Single), XmlConstants.EdmSingleTypeName); 
                    case TokenId.GuidLiteral:
                        return this.ParseTypedLiteral(typeof(Guid), XmlConstants.EdmGuidTypeName); 
                    case TokenId.BinaryLiteral:
                        return this.ParseTypedLiteral(typeof(byte[]), XmlConstants.EdmBinaryTypeName);
                    case TokenId.OpenParen:
                        return this.ParseParenExpression(); 
                    default:
                        throw ParseError(Strings.RequestQueryParser_ExpressionExpected(this.CurrentToken.Position)); 
                } 
            }
 
            /// Handles parenthesized expressions.
            /// The parsed expression.
            private Expression ParseParenExpression()
            { 
                if (this.CurrentToken.Id != TokenId.OpenParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_OpenParenExpected(this.CurrentToken.Position)); 
                }
 
                this.lexer.NextToken();
                Expression e = this.ParseExpression();
                if (this.CurrentToken.Id != TokenId.CloseParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_CloseParenOrOperatorExpected(this.CurrentToken.Position));
                } 
 
                this.lexer.NextToken();
                return e; 
            }

            /// Handles identifiers.
            /// The parsed expression. 
            private Expression ParseIdentifier()
            { 
                this.ValidateToken(TokenId.Identifier); 
                bool identifierIsFunction = this.lexer.PeekNextToken().Id == TokenId.OpenParen;
                if (identifierIsFunction) 
                {
                    return this.ParseIdentifierAsFunction();
                }
                else 
                {
                    return this.ParseMemberAccess(this.it); 
                } 
            }
 
            /// Handles identifiers which have been recognized as functions.
            /// The parsed expression.
            private Expression ParseIdentifierAsFunction()
            { 
                FunctionDescription[] functionDescriptions;
                Token functionToken = this.CurrentToken; 
                if (!functions.TryGetValue(functionToken.Text, out functionDescriptions)) 
                {
                    throw ParseError(Strings.RequestQueryParser_UnknownFunction(functionToken.Text, functionToken.Position)); 
                }

                this.lexer.NextToken();
                Expression[] originalArguments = this.ParseArgumentList(); 
                Expression[] arguments = this.nullPropagationRequired ? originalArguments : (Expression[])originalArguments.Clone();
                FunctionDescription function = this.FindBestFunction(functionDescriptions, ref arguments); 
                if (function == null) 
                {
                    string message = Strings.RequestQueryParser_NoApplicableFunction( 
                        functionToken.Text,
                        functionToken.Position,
                        FunctionDescription.BuildSignatureList(functionToken.Text, functionDescriptions));
                    throw ParseError(message); 
                }
 
                // Special case for null propagation - we never strip nullability from expressions. 
                if (this.nullPropagationRequired && function.IsTypeCast)
                { 
                    Expression typeExpression = arguments[arguments.Length - 1];
                    Debug.Assert(typeExpression != null, "typeExpression != null -- otherwise function finding failed.");
                    Debug.Assert(typeExpression.Type == typeof(Type), "typeExpression.Type == typeof(Type) -- last argument is always type.");
                    Type castTargetType = (Type)((ConstantExpression)typeExpression).Value; 
                    if (!TypeAllowsNull(castTargetType))
                    { 
                        arguments[arguments.Length - 1] = Expression.Constant(typeof(Nullable<>).MakeGenericType(castTargetType)); 
                    }
                } 

                Expression result = function.ConversionFunction(this.it, arguments);
                if (this.nullPropagationRequired && !function.IsTypeCheck && !function.IsTypeCast)
                { 
                    Debug.Assert(
                        originalArguments != arguments, 
                        "originalArguments != arguments -- arguments should have been cloned"); 
                    Debug.Assert(
                        originalArguments.Length == arguments.Length, 
                        "originalArguments.Length == arguments.Length -- arguments should not be added/removed");
                    for (int i = 0; i < originalArguments.Length; i++)
                    {
                        result = this.ConsiderNullPropagation(originalArguments[i], result); 
                    }
                } 
 
                return result;
            } 

            /// Handles boolean literals.
            /// The parsed expression.
            private Expression ParseBooleanLiteral() 
            {
                Debug.Assert(this.CurrentToken.Id == TokenId.BooleanLiteral, "this.CurrentToken.Id == TokenId.BooleanLiteral"); 
                string originalText = this.CurrentToken.Text; 
                this.lexer.NextToken();
                if (originalText == ExpressionConstants.KeywordTrue) 
                {
                    return trueLiteral;
                }
                else 
                {
                    Debug.Assert(originalText == ExpressionConstants.KeywordFalse, "originalText == ExpressionConstants.KeywordFalse"); 
                    return falseLiteral; 
                }
            } 

            /// Handles typed literals.
            /// Expected type to be parsed.
            /// Expected type name. 
            /// The constants expression produced by building the given literal.
            private Expression ParseTypedLiteral(Type targetType, string targetTypeName) 
            { 
                object targetValue;
                if (!WebConvert.TryKeyStringToPrimitive(this.CurrentToken.Text, targetType, out targetValue)) 
                {
                    string message = Strings.RequestQueryParser_UnrecognizedLiteral(targetTypeName, this.CurrentToken.Text, this.CurrentToken.Position);
                    throw ParseError(message);
                } 

                Expression result = this.CreateLiteral(targetValue, this.CurrentToken.Text); 
                this.lexer.NextToken(); 
                return result;
            } 

            /// Handles 'null' literals.
            /// The parsed expression.
            private Expression ParseNullLiteral() 
            {
                Debug.Assert(this.CurrentToken.Id == TokenId.NullLiteral, "this.CurrentToken.Id == TokenId.NullLiteral"); 
                this.lexer.NextToken(); 
                return NullLiteral;
            } 

            /// Handles member access.
            /// Instance being accessed.
            /// The parsed expression. 
            private Expression ParseMemberAccess(Expression instance)
            { 
                Debug.Assert(instance != null, "instance != null"); 

                Type type = instance.Type; 
                int errorPos = this.lexer.Position;
                string id = this.CurrentToken.GetIdentifier();
                this.lexer.NextToken();
 
                // An open paren here would indicate calling a method in regular C# syntax.
                ResourceProperty property = this.FindProperty(type, id); 
                if (property != null) 
                {
                    // We have a strongly-type property. 
                    Expression result = this.ConsiderNullPropagation(instance, Expression.Property(instance, property.PropertyInfo));
                    if (property.ResourceContainer != null)
                    {
                        Expression filter = DataServiceConfiguration.ComposeQueryInterceptors(this.service, property.ResourceContainer); 
                        if (filter != null)
                        { 
                            // We did null propagation for accessing the property, but we may also need 
                            // to do null propagation on the property value itself (otherwise the interception
                            // lambda needs to check the argument for null, which is probably unexpected). 
                            result = RequestQueryProcessor.ComposePropertyNavigation(
                                result, (LambdaExpression)filter, this.provider.NullPropagationRequired);
                        }
                    } 

                    return result; 
                } 
                else
                { 
                    // Open types can have any members inside them
#if ASTORIA_OPEN_OBJECT

                    if (type == typeof(object) || OpenTypeAttribute.IsOpenType(type)) 
                    {
                        // object LateBoundMethods.GetValue(object, string) 
                        Expression call = 
                            Expression.Call(null /* instance */, LateBoundMethods.GetValueMethodInfo, instance, Expression.Constant(id));
                        return this.ConsiderNullPropagation(instance, call); 
                    }
                    else
#endif
                    { 
                        throw ParseError(Strings.RequestQueryParser_UnknownProperty(id, this.GetTypeName(type), errorPos));
                    } 
                } 
            }
 
            /// Handles argument lists.
            /// The parsed expressions.
            private Expression[] ParseArgumentList()
            { 
                if (this.CurrentToken.Id != TokenId.OpenParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_OpenParenExpected(this.CurrentToken.Position)); 
                }
 
                this.lexer.NextToken();
                Expression[] args = this.CurrentToken.Id != TokenId.CloseParen ? this.ParseArguments() : emptyExpressions;
                if (this.CurrentToken.Id != TokenId.CloseParen)
                { 
                    throw ParseError(Strings.RequestQueryParser_CloseParenOrCommaExpected(this.CurrentToken.Position));
                } 
 
                this.lexer.NextToken();
                return args; 
            }

            /// Handles comma-separated arguments.
            /// The parsed expressions. 
            private Expression[] ParseArguments()
            { 
                List argList = new List(); 
                while (true)
                { 
                    argList.Add(this.ParseExpression());
                    if (this.CurrentToken.Id != TokenId.Comma)
                    {
                        break; 
                    }
 
                    this.lexer.NextToken(); 
                }
 
                return argList.ToArray();
            }

            #endregion Parsing. 

            /// Creates a constant expression with the specified literal. 
            /// Constant value. 
            /// Value text.
            /// The created expression. 
            private Expression CreateLiteral(object value, string text)
            {
                ConstantExpression expr = Expression.Constant(value);
                this.literals.Add(expr, text); 
                return expr;
            } 
 
            /// Finds the best fitting function for the specified arguments.
            /// Functions to consider. 
            /// Arguments; if a best function is found, promoted arguments.
            /// The best fitting function; null if none found or ambiguous.
            private FunctionDescription FindBestFunction(FunctionDescription[] functions, ref Expression[] arguments)
            { 
                Debug.Assert(functions != null, "functions != null");
                List applicableFunctions = new List(functions.Length); 
                List applicablePromotedArguments = new List(functions.Length); 

                // Build a list of applicable functions (and cache their promoted arguments). 
                foreach (FunctionDescription candidate in functions)
                {
                    if (candidate.ParameterTypes.Length != arguments.Length)
                    { 
                        continue;
                    } 
 
                    Expression[] promotedArguments = new Expression[arguments.Length];
                    bool argumentsMatch = true; 
                    for (int i = 0; i < candidate.ParameterTypes.Length; i++)
                    {
                        promotedArguments[i] = this.PromoteExpression(arguments[i], candidate.ParameterTypes[i], true);
                        if (promotedArguments[i] == null) 
                        {
                            argumentsMatch = false; 
                            break; 
                        }
                    } 

                    if (argumentsMatch)
                    {
                        applicableFunctions.Add(candidate); 
                        applicablePromotedArguments.Add(promotedArguments);
                    } 
                } 

                // Return the best applicable function. 
                if (applicableFunctions.Count == 0)
                {
                    // No matching function.
                    return null; 
                }
                else if (applicableFunctions.Count == 1) 
                { 
                    arguments = applicablePromotedArguments[0];
                    return applicableFunctions[0]; 
                }
                else
                {
                    // Find a single function which is better than all others. 
                    int bestFunctionIndex = -1;
                    for (int i = 0; i < applicableFunctions.Count; i++) 
                    { 
                        bool betterThanAllOthers = true;
                        for (int j = 0; j < applicableFunctions.Count; j++) 
                        {
                            if (i != j && IsBetterThan(arguments, applicableFunctions[j].ParameterTypes, applicableFunctions[i].ParameterTypes))
                            {
                                betterThanAllOthers = false; 
                                break;
                            } 
                        } 

                        if (betterThanAllOthers) 
                        {
                            if (bestFunctionIndex == -1)
                            {
                                bestFunctionIndex = i; 
                            }
                            else 
                            { 
                                // Ambiguous.
                                return null; 
                            }
                        }
                    }
 
                    if (bestFunctionIndex == -1)
                    { 
                        return null; 
                    }
 
                    arguments = applicablePromotedArguments[bestFunctionIndex];
                    return applicableFunctions[bestFunctionIndex];
                }
            } 

            /// Rewrites an expression to propagate null values if necessary. 
            /// Expression to check for null. 
            /// Expression to yield if  does not yield null.
            /// The possibly rewriteen . 
            private Expression ConsiderNullPropagation(Expression element, Expression notNullExpression)
            {
                if (!this.nullPropagationRequired || element == this.it || !TypeAllowsNull(element.Type))
                { 
                    return notNullExpression;
                } 
 
                // Tiny optimization: remove the check on constants which are known not to be null.
                // Otherwise every string literal propagates out, which is correct but unnecessarily messy. 
                if (element is ConstantExpression && element != NullLiteral)
                {
                    return notNullExpression;
                } 

                // ifTrue and ifFalse expressions must match exactly. We need to ensure that the 'false' 
                // side is nullable, and the 'true' side is a null of the correct type. 
                Expression test = Expression.Equal(element, Expression.Constant(null, element.Type));
                Expression falseIf = notNullExpression; 
                if (!TypeAllowsNull(falseIf.Type))
                {
                    falseIf = Expression.Convert(falseIf, typeof(Nullable<>).MakeGenericType(falseIf.Type));
                } 

                Expression trueIf = Expression.Constant(null, falseIf.Type); 
                return Expression.Condition(test, trueIf, falseIf); 
            }
 
            /// Checks that the operand (possibly promoted) is valid for the specified operation.
            /// Type with signatures to match.
            /// Name of operation for error reporting.
            /// Expression for operand. 
            /// Position for error reporting.
            private void CheckAndPromoteOperand(Type signatures, string operationName, ref Expression expr, int errorPos) 
            { 
                Debug.Assert(signatures != null, "signatures != null");
                Debug.Assert(operationName != null, "operationName != null"); 
                Expression[] args = new Expression[] { expr };
                MethodBase method;
                if (this.FindMethod(signatures, "F", args, out method) != 1)
                { 
                    throw ParseError(Strings.RequestQueryParser_IncompatibleOperand(operationName, this.GetTypeName(args[0].Type), errorPos));
                } 
 
                expr = args[0];
            } 

            /// Checks that the operands (possibly promoted) are valid for the specified operation.
            /// Type with signatures to match.
            /// Name of operation for error reporting. 
            /// Expression for left operand.
            /// Expression for right operand. 
            /// Position for error reporting. 
            private void CheckAndPromoteOperands(Type signatures, string operationName, ref Expression left, ref Expression right, int errorPos)
            { 
                Expression[] args = new Expression[] { left, right };
                MethodBase method;
                if (this.FindMethod(signatures, "F", args, out method) != 1)
                { 
                    throw this.IncompatibleOperandsError(operationName, left, right, errorPos);
                } 
 
                left = args[0];
                right = args[1]; 
            }

            /// Finds a property in the specified type with the given name.
            /// Type in which to look for member. 
            /// Member name.
            /// The ResourceProperty for the specified type. 
            private ResourceProperty FindProperty(Type type, string memberName) 
            {
                // This could also be a FindPropertyOrField method. 
                Debug.Assert(type != null, "type != null");
                Debug.Assert(memberName != null, "memberName != null");

                ResourceProperty property = this.provider.TryResolvePropertyName(type, memberName); 
                if (property != null)
                { 
                    if (property.ResourceContainer != null) 
                    {
                        this.service.Configuration.CheckResourceRightsForRead(property.ResourceContainer, true /* singleResult */); 
                    }

                    return property;
                } 
                else
                { 
                    return null; 
                }
            } 

            /// Finds the named method in the specifid type.
            /// Type to look in.
            /// Name of method to look for. 
            /// Arguments to method.
            /// Best method found. 
            /// Number of matching methods. 
            private int FindMethod(Type type, string methodName, Expression[] args, out MethodBase method)
            { 
                BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance;
                foreach (Type t in SelfAndBaseTypes(type))
                {
                    MemberInfo[] members = t.FindMembers(MemberTypes.Method, flags, Type.FilterName, methodName); 
                    int count = this.FindBestMethod(members.Cast(), args, out method);
                    if (count != 0) 
                    { 
                        return count;
                    } 
                }

                method = null;
                return 0; 
            }
 
            /// Finds all applicable methods from the specified enumeration that match the arguments. 
            /// Enumerable object of candidate methods.
            /// Argument expressions. 
            /// Methods that apply to the specified arguments.
            private MethodData[] FindApplicableMethods(IEnumerable methods, Expression[] args)
            {
                List result = new List(); 
                foreach (MethodBase method in methods)
                { 
                    MethodData methodData = new MethodData(method, method.GetParameters()); 
                    if (this.IsApplicable(methodData, args))
                    { 
                        result.Add(methodData);
                    }
                }
 
                return result.ToArray();
            } 
 
            /// Finds the best methods for the specified arguments given a candidate method enumeration.
            /// Enumerable object for candidate methods. 
            /// Argument expressions to match.
            /// Best matched method.
            /// The number of "best match" methods.
            private int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method) 
            {
                MethodData[] applicable = this.FindApplicableMethods(methods, args); 
                if (applicable.Length > 1) 
                {
                    applicable = FindBestApplicableMethods(applicable, args); 
                }

                int result = applicable.Length;
                method = null; 
                if (applicable.Length == 1)
                { 
                    // If we started off with all non-OpenType expressions and end with all-OpenType 
                    // expressions, we've been too aggresive - the transition from non-open-types
                    // to open types should initially happen only as a result of accessing open properties. 
#if ASTORIA_OPEN_OBJECT
                    MethodData md = applicable[0];
                    bool originalArgsDefined = true;
                    bool promotedArgsOpen = true; 
                    for (int i = 0; i < args.Length; i++)
                    { 
                        originalArgsDefined = originalArgsDefined && !IsOpenPropertyExpression(args[i]); 
                        promotedArgsOpen = promotedArgsOpen && md.Parameters[i].ParameterType == typeof(object);
                        args[i] = md.Args[i]; 
                    }

                    method = (originalArgsDefined && promotedArgsOpen) ? null : md.MethodBase;
                    result = (method == null) ? 0 : 1; 
#else
                    for (int i = 0; i < args.Length; i++) 
                    { 
                        args[i] = applicable[0].Args[i];
                    } 

                    method = applicable[0].MethodBase;
                    result = 1;
#endif 
                }
                else if (applicable.Length > 1) 
                { 
                    // We may have the case for operators (which C# doesn't) in which we have a nullable operand
                    // and a non-nullable operand. We choose to convert the one non-null operand to nullable in that 
                    // case (the binary expression will lift to null).
                    if (args.Length == 2 && applicable.Length == 2 &&
                        GetNonNullableType(applicable[0].Parameters[0].ParameterType) ==
                        GetNonNullableType(applicable[1].Parameters[0].ParameterType)) 
                    {
                        MethodData nullableMethod = 
                            TypeAllowsNull(applicable[0].Parameters[0].ParameterType) ? 
                            applicable[0] :
                            applicable[1]; 
                        args[0] = nullableMethod.Args[0];
                        args[1] = nullableMethod.Args[1];
                        return this.FindBestMethod(methods, args, out method);
                    } 
                }
 
                return result; 
            }
 
            /// Gets a name that can be used for error messages.
            /// Type to get name for.
            /// The name of the specified .
            private string GetTypeName(Type type) 
            {
                Debug.Assert(type != null, "type != null"); 
                return WebUtil.GetTypeName(this.provider, type); 
            }
 
            /// Creates an exception indicated that two operands are incompatible.
            /// Name of operation for operands.
            /// Expression for left-hand operand.
            /// Expression for right-hand operand. 
            /// Position for error.
            /// A new . 
            private Exception IncompatibleOperandsError(string operationName, Expression left, Expression right, int pos) 
            {
                string message = Strings.RequestQueryParser_IncompatibleOperands( 
                    operationName,
                    this.GetTypeName(left.Type),
                    this.GetTypeName(right.Type),
                    pos); 
                return ParseError(message);
            } 
 
            /// Checks whether the specified method is applicable given the argument expressions.
            /// Method to check. 
            /// Argument expressions.
            /// true if the method is applicable; false otherwise.
            private bool IsApplicable(MethodData method, Expression[] args)
            { 
                if (method.Parameters.Length != args.Length)
                { 
                    return false; 
                }
 
                Expression[] promotedArgs = new Expression[args.Length];
                for (int i = 0; i < args.Length; i++)
                {
                    ParameterInfo pi = method.Parameters[i]; 
                    Debug.Assert(!pi.IsOut, "!pi.IsOut");
                    Expression promoted = this.PromoteExpression(args[i], pi.ParameterType, false); 
                    if (promoted == null) 
                    {
                        return false; 
                    }

                    promotedArgs[i] = promoted;
                } 

                method.Args = promotedArgs; 
                return true; 
            }
 
            /// Promotes the specified expression to the given type if necessary.
            /// Expression to promote.
            /// Type to change expression to.
            /// Whether an exact type is required; false implies a compatible type is OK. 
            /// Expression with the promoted type.
            private Expression PromoteExpression(Expression expr, Type type, bool exact) 
            { 
                Debug.Assert(expr != null, "expr != null");
                Debug.Assert(type != null, "type != null"); 
                if (expr.Type == type)
                {
                    return expr;
                } 

                ConstantExpression ce = expr as ConstantExpression; 
                if (ce != null) 
                {
                    if (ce == NullLiteral) 
                    {
                        if (TypeAllowsNull(type))
                        {
                            return Expression.Constant(null, type); 
                        }
                    } 
                    else 
                    {
                        string text; 
                        if (this.literals.TryGetValue(ce, out text))
                        {
                            Type target = GetNonNullableType(type);
                            object value = null; 
                            if (ce.Type == typeof(string) && target == typeof(Type))
                            { 
                                if (WebConvert.TryRemoveQuotes(ref text)) 
                                {
                                    ResourceType resourceType = this.provider.TryResolveTypeName(text); 
                                    if (resourceType != null)
                                    {
                                        value = resourceType.Type;
                                    } 
                                }
                            } 
                            else 
                            {
                                switch (Type.GetTypeCode(ce.Type)) 
                                {
                                    case TypeCode.Int32:
                                    case TypeCode.Int64:
                                        value = ParseNumber(text, target); 
                                        break;
                                    case TypeCode.Double: 
                                        if (target == typeof(decimal)) 
                                        {
                                            value = ParseNumber(text, target); 
                                        }

                                        break;
                                } 
                            }
 
                            if (value != null) 
                            {
                                return Expression.Constant(value, type); 
                            }
                        }
                    }
                } 

                if (IsCompatibleWith(expr.Type, type)) 
                { 
                    if (type.IsValueType || exact)
                    { 
                        return Expression.Convert(expr, type);
                    }

                    return expr; 
                }
 
                // Allow promotion from nullable to non-nullable by directly accessing underlying value. 
                if (IsNullableType(expr.Type) && type.IsValueType)
                { 
                    Expression valueAccessExpression = Expression.Property(expr, "Value");
                    valueAccessExpression = this.PromoteExpression(valueAccessExpression, type, exact);
                    return valueAccessExpression;
                } 

                return null; 
            } 

            /// Checks that the current token has the specified identifier. 
            /// Identifier to check.
            /// true if the current token is an identifier with the specified text.
            private bool TokenIdentifierIs(string id)
            { 
                return this.CurrentToken.IdentifierIs(id);
            } 
 
            /// Validates the current token is of the specified kind.
            /// Expected token kind. 
            private void ValidateToken(TokenId t)
            {
                if (this.CurrentToken.Id != t)
                { 
                    throw ParseError(Strings.RequestQueryParser_SyntaxError(this.CurrentToken.Position));
                } 
            } 

            #region Recursion control. 

            /// Marks the fact that a recursive method was entered, and checks that the depth is allowed.
            private void RecurseEnter()
            { 
                this.recursionDepth++;
                Debug.Assert(this.recursionDepth <= RecursionLimit, "this.recursionDepth <= recursionLimit"); 
                if (this.recursionDepth == RecursionLimit) 
                {
                    throw DataServiceException.CreateDeepRecursion(RecursionLimit); 
                }
            }

            /// Marks the fact that a recursive method is leaving.. 
            private void RecurseLeave()
            { 
                this.recursionDepth--; 
                Debug.Assert(0 <= this.recursionDepth, "0 <= this.recursionDepth");
                Debug.Assert(this.recursionDepth < RecursionLimit, "this.recursionDepth < recursionLimit"); 
            }

            #endregion Recursion control.
 
            /// Use this class to encapsulate method information.
            [DebuggerDisplay("MethodData {methodBase}")] 
            private class MethodData 
            {
                #region Private fields. 

                /// Described method.
                private readonly MethodBase methodBase;
 
                /// Parameters for method.
                private readonly ParameterInfo[] parameters; 
 
                /// Argument expressions.
                private Expression[] args; 

                #endregion Private fields.

                #region Constructors. 

                /// Initializes a new  instance. 
                /// Described method 
                /// Parameters for method.
                public MethodData(MethodBase method, ParameterInfo[] parameters) 
                {
                    this.methodBase = method;
                    this.parameters = parameters;
                } 

                #endregion Constructors. 
 
                #region Properties.
 
                /// Argument expressions.
                public Expression[] Args
                {
                    get { return this.args; } 
                    set { this.args = value; }
                } 
 
                /// Described method.
                public MethodBase MethodBase 
                {
                    get { return this.methodBase; }
                }
 
                /// Parameters for method.
                public ParameterInfo[] Parameters 
                { 
                    get { return this.parameters; }
                } 

                /// Enumeration of parameter types.
                public IEnumerable ParameterTypes
                { 
                    get
                    { 
                        foreach (ParameterInfo parameter in this.Parameters) 
                        {
                            yield return parameter.ParameterType; 
                        }
                    }
                }
 
                #endregion Properties.
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK