Beispiel #1
0
 static Token()
 {
     Token token = new Token {
         Text = "gt",
         Id = TokenId.Identifier,
         Position = 0
     };
     GreaterThan = token;
     Token token2 = new Token {
         Text = "eq",
         Id = TokenId.Identifier,
         Position = 0
     };
     EqualsTo = token2;
     Token token3 = new Token {
         Text = "lt",
         Id = TokenId.Identifier,
         Position = 0
     };
     LessThan = token3;
 }
Beispiel #2
0
 private void ExpandIdentifier(Func<bool> expander, bool ignoreWs)
 {
     if (this.token.Id == TokenId.Identifier)
     {
         int textPos = this.textPos;
         char ch = this.ch;
         Token token = this.token;
         bool ignoreWhitespace = this.ignoreWhitespace;
         this.ignoreWhitespace = ignoreWs;
         int position = this.token.Position;
         if (expander())
         {
             this.token.Text = this.text.Substring(position, this.textPos - position);
             this.token.Position = position;
         }
         else
         {
             this.textPos = textPos;
             this.ch = ch;
             this.token = token;
         }
         this.ignoreWhitespace = ignoreWhitespace;
     }
 }
        /// <summary>Returns the next token without advancing the lexer.</summary>
        /// <returns>The next token.</returns>
        internal Token PeekNextToken()
        {
            int savedTextPos = this.textPos;
            char savedChar = this.ch;
            Token savedToken = this.token;

            this.NextToken();
            Token result = this.token;

            this.textPos = savedTextPos;
            this.ch = savedChar;
            this.token = savedToken;

            return result;
        }
            /// <summary>Handles -, not unary operators.</summary>
            /// <returns>The parsed expression.</returns>
            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);
                        expr = GenerateNegate(expr);
                    }
                    else
                    {
                        this.CheckAndPromoteOperand(typeof(OperationSignatures.INotSignatures), op.Text, ref expr, op.Position);
                        expr = GenerateNot(expr);
                    }

                    this.RecurseLeave();
                    return expr;
                }

                this.RecurseLeave();
                return this.ParsePrimary();
            }
            /// <summary>
            /// Given left and right hand side expressions, generates a comparison expression based
            /// on the given comparison token
            /// </summary>
            /// <param name="left">Left hand side expression</param>
            /// <param name="right">Right hand side expression</param>
            /// <param name="op">Comparison operator</param>
            /// <returns>Resulting comparison expression</returns>
            private Expression GenerateComparisonExpression(Expression left, Expression right, Token op)
            {
                bool equality = op.IsEqualityOperator;
                if (equality && !left.Type.IsValueType && !right.Type.IsValueType)
                {
                    if (left.Type != right.Type)
                    {
                        if (WebUtil.IsNullConstant(left))
                        {
                            left = Expression.Constant(null, right.Type);
                        }
                        else if (WebUtil.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 ExpressionParser.IncompatibleOperandsError(op.Text, left, right, op.Position);
                        }
                    }
                }
                else if (left == WebUtil.NullLiteral || right == WebUtil.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 (!WebUtil.TypeAllowsNull(left.Type))
                    {
                        left = Expression.Convert(left, typeof(Nullable<>).MakeGenericType(left.Type));
                    }
                    else if (!WebUtil.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");
                MethodInfo comparisonMethodInfo = null;
                if (!equality)
                {
                    if (left.Type == typeof(string))
                    {
                        comparisonMethodInfo = StringCompareMethodInfo;
                    }
                    else
                        if (left.Type == typeof(bool))
                        {
                            comparisonMethodInfo = BoolCompareMethodInfo;
                        }
                        else if (left.Type == typeof(bool?))
                        {
                            comparisonMethodInfo = BoolCompareMethodInfoNullable;
                        }
                        else
                            if (left.Type == typeof(Guid))
                            {
                                comparisonMethodInfo = GuidCompareMethodInfo;
                            }
                            else
                                if (left.Type == typeof(Guid?))
                                {
                                    comparisonMethodInfo = GuidCompareMethodInfoNullable;
                                }
                }

                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, comparisonMethodInfo);
                        break;
                    case ExpressionConstants.KeywordGreaterThanOrEqual:
                        left = GenerateGreaterThanEqual(left, right, comparisonMethodInfo);
                        break;
                    case ExpressionConstants.KeywordLessThan:
                        left = GenerateLessThan(left, right, comparisonMethodInfo);
                        break;
                    case ExpressionConstants.KeywordLessThanOrEqual:
                        left = GenerateLessThanEqual(left, right, comparisonMethodInfo);
                        break;
                }

                return left;
            }
            /// <summary>
            /// Generates a comparison expression which can handle NULL values for any type.
            /// NULL is always treated as the smallest possible value.
            /// So for example for strings NULL is smaller than any non-NULL string.
            /// For now only GreaterThan and LessThan operators are supported by this method.
            /// </summary>
            /// <param name="left">Left hand side expression</param>
            /// <param name="rightLiteral">Literal for the right hand side</param>
            /// <param name="op">gt or lt operator token</param>
            /// <returns>Resulting comparison expression (has a Boolean value)</returns>
            private Expression GenerateNullAwareComparison(Expression left, String rightLiteral, Token op)
            {
                Debug.Assert(
                    op.Text == ExpressionConstants.KeywordGreaterThan || op.Text == ExpressionConstants.KeywordLessThan,
                    "Only GreaterThan or LessThan operators are supported by the GenerateNullAwateComparison method for now.");

                ExpressionLexer l = new ExpressionLexer(rightLiteral);
                Expression right = this.ParsePrimaryStart(l);

                if (WebUtil.TypeAllowsNull(left.Type))
                {
                    if (!WebUtil.TypeAllowsNull(right.Type))
                    {
                        right = Expression.Convert(right, typeof(Nullable<>).MakeGenericType(right.Type));
                    }
                }
                else if (WebUtil.TypeAllowsNull(right.Type))
                {
                    left = Expression.Convert(left, typeof(Nullable<>).MakeGenericType(left.Type));
                }
                else
                {
                    // Can't perform NULL aware comparison on this type. Just let the normal 
                    // comparison deal with it. Since the type doesn't allow NULL one should 
                    // never appear, so normal comparison is just fine.
                    return this.GenerateComparisonExpression(left, right, op);
                }

                switch (op.Text)
                {
                    case ExpressionConstants.KeywordGreaterThan:
                        // (left != null) && ((right == null) || Compare(left, right) > 0)
                        if (left == WebUtil.NullLiteral)
                        {
                            return Expression.Constant(false, typeof(bool));
                        }
                        else if (right == WebUtil.NullLiteral)
                        {
                            return GenerateNotEqual(left, Expression.Constant(null, left.Type));
                        }
                        else
                        {
                            return GenerateLogicalAnd(
                                        GenerateNotEqual(left, Expression.Constant(null, left.Type)),
                                        GenerateLogicalOr(
                                            GenerateEqual(right, Expression.Constant(null, right.Type)),
                                            this.GenerateComparisonExpression(left, right, op)));
                        }

                    case ExpressionConstants.KeywordLessThan:
                        // (right != null) && ((left == null) || Compare(left, right) < 0)
                        if (right == WebUtil.NullLiteral)
                        {
                            return Expression.Constant(false, typeof(bool));
                        }
                        else if (left == WebUtil.NullLiteral)
                        {
                            return GenerateNotEqual(right, Expression.Constant(null, right.Type));
                        }
                        else
                        {
                            return GenerateLogicalAnd(
                                        GenerateNotEqual(right, Expression.Constant(null, left.Type)),
                                        GenerateLogicalOr(
                                            GenerateEqual(left, Expression.Constant(null, right.Type)),
                                            this.GenerateComparisonExpression(left, right, op)));
                        }

                    default:
                        // For now only < and > are supported as we use this only from $skiptoken
                        throw ParseError(
                            Strings.RequestQueryParser_NullOperatorUnsupported(op.Text, op.Position, this.lexer.ExpressionText));
                }
            }
 /// <summary>
 /// Generates a comparison expression given a left hand side expression and literal for right hand side
 /// </summary>
 /// <param name="left">Left hand side experssions</param>
 /// <param name="rightLiteral">Literal for right hand side</param>
 /// <param name="op">gt, eq or lt operator token</param>
 /// <returns>Resulting comparison expression</returns>
 private Expression GenerateComparison(Expression left, String rightLiteral, Token op)
 {
     ExpressionLexer l = new ExpressionLexer(rightLiteral);
     return this.GenerateComparisonExpression(left, this.ParsePrimaryStart(l), op);
 }
 /// <summary>Checks that the given token has the specified identifier.</summary>
 /// <param name="token">Token to check</param>
 /// <param name="id">Identifier to check.</param>
 /// <returns>true if <paramref name="token"/> is an identifier with the specified text.</returns>
 private static bool TokenIdentifierIs(Token token, string id)
 {
     return token.Id == TokenId.Identifier && String.Equals(id, token.Text, StringComparison.OrdinalIgnoreCase);
 }
Beispiel #9
0
 internal Token PeekNextToken()
 {
     int textPos = this.textPos;
     char ch = this.ch;
     Token token = this.token;
     this.NextToken();
     Token token2 = this.token;
     this.textPos = textPos;
     this.ch = ch;
     this.token = token;
     return token2;
 }