Expressions.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Activities / Rules / Expressions.cs / 1305376 / Expressions.cs

                            // ---------------------------------------------------------------------------- 
// Copyright (C) 2006 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------

#define CODE_ANALYSIS 
using System.CodeDom;
using System.Collections.Generic; 
using System.Diagnostics.CodeAnalysis; 
using System.Globalization;
using System.Reflection; 
using System.Text;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities.Common; 

namespace System.Workflow.Activities.Rules 
{ 
    public interface IRuleExpression
    { 
        RuleExpressionInfo Validate(RuleValidation validation, bool isWritten);
        RuleExpressionResult Evaluate(RuleExecution execution);
        void AnalyzeUsage(RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier);
        [SuppressMessage("Microsoft.Naming", "CA1720:AvoidTypeNamesInParameters", MessageId = "0#")] 
        void Decompile(StringBuilder stringBuilder, CodeExpression parentExpression);
        bool Match(CodeExpression expression); 
        CodeExpression Clone(); 
    }
 
    internal abstract class RuleExpressionInternal
    {
        internal abstract RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten);
        internal abstract RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution); 
        internal abstract void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier);
        internal abstract void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression); 
        internal abstract bool Match(CodeExpression leftExpression, CodeExpression rightExpression); 
        internal abstract CodeExpression Clone(CodeExpression expression);
    } 


    #region "this" expression
 
    // CodeThisReferenceExpression
    internal class ThisExpression : RuleExpressionInternal 
    { 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            if (isWritten)
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeThisReferenceExpression).ToString());
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = expression;
                validation.Errors.Add(error); 
                return null; 
            }
 
            return new RuleExpressionInfo(validation.ThisType);
        }

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            if (analysis.ForWrites && !isWritten)            // If we're tracking writes, then ignore things that aren't written. 
                return; 
            else if (!analysis.ForWrites && !isRead)   // ... and vice-versa
                return; 

            StringBuilder sb = new StringBuilder("this/");
            for (RulePathQualifier q = qualifier; q != null; q = q.Next)
            { 
                sb.Append(q.Name);
                if (q.Name == "*") 
                { 
                    if (q.Next != null)
                        throw new NotSupportedException(Messages.InvalidWildCardInPathQualifier); 
                }
                else
                {
                    sb.Append("/"); 
                }
            } 
 
            // Add the symbol to our set.
            analysis.AddSymbol(sb.ToString()); 
        }

        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        { 
            return execution.ThisLiteralResult;
        } 
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        { 
            stringBuilder.Append("this");
        }

        internal override CodeExpression Clone(CodeExpression expression) 
        {
            return new CodeThisReferenceExpression(); 
        } 

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            // We already verified their types match.
            return true;
        } 
    }
 
    #endregion 

    #region Primitive expression 

    // CodePrimitiveExpression
    internal class PrimitiveExpression : RuleExpressionInternal
    { 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            if (isWritten) 
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodePrimitiveExpression).ToString()); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget);
                error.UserData[RuleUserDataKeys.ErrorObject] = expression;
                validation.Errors.Add(error);
                return null; 
            }
 
            CodePrimitiveExpression primitiveExpr = (CodePrimitiveExpression)expression; 
            Type resultType = (primitiveExpr.Value != null) ? primitiveExpr.Value.GetType() : typeof(NullLiteral);
            return new RuleExpressionInfo(resultType); 
        }

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
        { 
            // Literal values have no interesting dependencies or side-effects.
        } 
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        { 
            CodePrimitiveExpression primitiveExpr = (CodePrimitiveExpression)expression;
            return new RuleLiteralResult(primitiveExpr.Value);
        }
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        { 
            CodePrimitiveExpression primitiveExpr = (CodePrimitiveExpression)expression; 
            RuleDecompiler.DecompileObjectLiteral(stringBuilder, primitiveExpr.Value);
        } 

        internal override CodeExpression Clone(CodeExpression expression)
        {
            CodePrimitiveExpression primitiveExpr = (CodePrimitiveExpression)expression; 
            object clonedValue = ConditionHelper.CloneObject(primitiveExpr.Value);
            return new CodePrimitiveExpression(clonedValue); 
        } 

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodePrimitiveExpression primitiveExpr = (CodePrimitiveExpression)expression;
            CodePrimitiveExpression comperandPrimitive = (CodePrimitiveExpression)comperand;
 
            if (primitiveExpr.Value == comperandPrimitive.Value)
                return true; 
 
            if (primitiveExpr.Value == null || comperandPrimitive.Value == null)
                return false; 

            return primitiveExpr.Value.Equals(comperandPrimitive.Value);
        }
    } 

    #endregion 
 
    #region Binary expression
 
    // CodeBinaryOperatorExpression
    internal class BinaryExpression : RuleExpressionInternal
    {
        #region Validate 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        {
            string message; 
            ValidationError error;

            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression;
 
            // Early exit from this if a cycle is detected.
            if (!validation.PushParentExpression(binaryExpr)) 
                return null; 

            if (isWritten) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeBinaryOperatorExpression).ToString());
                error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget);
                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                validation.Errors.Add(error);
            } 
 
            RuleExpressionInfo lhsExprInfo = null;
            RuleExpressionInfo rhsExprInfo = null; 

            if (binaryExpr.Left == null)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullBinaryOpLHS, binaryExpr.Operator.ToString()); 
                error = new ValidationError(message, ErrorNumbers.Error_LeftOperandMissing);
                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                validation.Errors.Add(error); 
            }
            else 
            {
                if (binaryExpr.Left is CodeTypeReferenceExpression)
                {
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, binaryExpr.Left.GetType().FullName); 
                    error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                    error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr.Left; 
                    validation.AddError(error); 
                    return null;
                } 

                lhsExprInfo = RuleExpressionWalker.Validate(validation, binaryExpr.Left, false);
            }
 
            if (binaryExpr.Right == null)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullBinaryOpRHS, binaryExpr.Operator.ToString()); 
                error = new ValidationError(message, ErrorNumbers.Error_RightOperandMissing);
                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                validation.Errors.Add(error);
            }
            else
            { 
                if (binaryExpr.Right is CodeTypeReferenceExpression)
                { 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, binaryExpr.Right.GetType().FullName); 
                    error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                    error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr.Right; 
                    validation.AddError(error);
                    return null;
                }
 
                rhsExprInfo = RuleExpressionWalker.Validate(validation, binaryExpr.Right, false);
            } 
 
            validation.PopParentExpression();
 
            RuleBinaryExpressionInfo resultExprInfo = null;

            if (lhsExprInfo != null && rhsExprInfo != null)
            { 
                Type lhsType = lhsExprInfo.ExpressionType;
                Type rhsType = rhsExprInfo.ExpressionType; 
 
                switch (binaryExpr.Operator)
                { 
                    case CodeBinaryOperatorType.Add:
                    case CodeBinaryOperatorType.Subtract:
                    case CodeBinaryOperatorType.Multiply:
                    case CodeBinaryOperatorType.Divide: 
                    case CodeBinaryOperatorType.Modulus:
                    case CodeBinaryOperatorType.BitwiseAnd: 
                    case CodeBinaryOperatorType.BitwiseOr: 
                        resultExprInfo = ArithmeticLiteral.ResultType(binaryExpr.Operator, lhsType, binaryExpr.Left, rhsType, binaryExpr.Right, validation, out error);
                        if (resultExprInfo == null) 
                        {
                            // check if constants are used with ulongs, as we should do some extra "conversions"
                            if (((lhsType == typeof(ulong)) && (PromotionPossible(rhsType, binaryExpr.Right)))
                                || ((rhsType == typeof(ulong)) && (PromotionPossible(lhsType, binaryExpr.Left)))) 
                            {
                                resultExprInfo = new RuleBinaryExpressionInfo(lhsType, rhsType, typeof(ulong)); 
                            } 
                            else
                            { 
                                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr;
                                validation.Errors.Add(error);
                            }
                        } 
                        break;
 
                    case CodeBinaryOperatorType.IdentityEquality: 
                    case CodeBinaryOperatorType.IdentityInequality:
                        resultExprInfo = new RuleBinaryExpressionInfo(lhsType, rhsType, typeof(bool)); 
                        break;

                    case CodeBinaryOperatorType.ValueEquality:
                        resultExprInfo = Literal.AllowedComparison(lhsType, binaryExpr.Left, rhsType, binaryExpr.Right, binaryExpr.Operator, validation, out error); 
                        if (resultExprInfo == null)
                        { 
                            // check if constants are used with ulongs, as we should do some extra "conversions" 
                            if (((lhsType == typeof(ulong)) && (PromotionPossible(rhsType, binaryExpr.Right)))
                                || ((rhsType == typeof(ulong)) && (PromotionPossible(lhsType, binaryExpr.Left)))) 
                            {
                                resultExprInfo = new RuleBinaryExpressionInfo(lhsType, rhsType, typeof(bool));
                            }
                            else 
                            {
                                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                                validation.Errors.Add(error); 
                            }
                        } 
                        break;

                    case CodeBinaryOperatorType.LessThan:
                    case CodeBinaryOperatorType.LessThanOrEqual: 
                    case CodeBinaryOperatorType.GreaterThan:
                    case CodeBinaryOperatorType.GreaterThanOrEqual: 
                        resultExprInfo = Literal.AllowedComparison(lhsType, binaryExpr.Left, rhsType, binaryExpr.Right, binaryExpr.Operator, validation, out error); 
                        if (resultExprInfo == null)
                        { 
                            // check if constants are used with ulongs, as we should do some extra "conversions"
                            if (((lhsType == typeof(ulong)) && (PromotionPossible(rhsType, binaryExpr.Right)))
                                || ((rhsType == typeof(ulong)) && (PromotionPossible(lhsType, binaryExpr.Left))))
                            { 
                                resultExprInfo = new RuleBinaryExpressionInfo(lhsType, rhsType, typeof(bool));
                            } 
                            else 
                            {
                                error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                                validation.Errors.Add(error);
                            }
                        }
                        break; 

                    case CodeBinaryOperatorType.BooleanAnd: 
                    case CodeBinaryOperatorType.BooleanOr: 
                        resultExprInfo = new RuleBinaryExpressionInfo(lhsType, rhsType, typeof(bool));
                        if (lhsType != typeof(bool)) 
                        {
                            message = string.Format(CultureInfo.CurrentCulture, Messages.LogicalOpBadTypeLHS, binaryExpr.Operator.ToString(),
                                (lhsType == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(lhsType));
                            error = new ValidationError(message, ErrorNumbers.Error_LeftOperandInvalidType); 
                            error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr;
                            validation.Errors.Add(error); 
                            resultExprInfo = null; 
                        }
                        if (rhsType != typeof(bool)) 
                        {
                            message = string.Format(CultureInfo.CurrentCulture, Messages.LogicalOpBadTypeRHS, binaryExpr.Operator.ToString(),
                                (rhsType == typeof(NullLiteral)) ? Messages.NullValue : RuleDecompiler.DecompileType(rhsType));
                            error = new ValidationError(message, ErrorNumbers.Error_RightOperandInvalidType); 
                            error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr;
                            validation.Errors.Add(error); 
                            resultExprInfo = null; 
                        }
                        break; 

                    default:
                        {
                            message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, binaryExpr.Operator.ToString()); 
                            error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                            error.UserData[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                            validation.Errors.Add(error); 
                        }
                        break; 
                }
            }

            // Validate any RuleAttributes, if present. 
            if (resultExprInfo != null)
            { 
                MethodInfo method = resultExprInfo.MethodInfo; 
                if (method != null)
                { 
                    object[] attrs = method.GetCustomAttributes(typeof(RuleAttribute), true);
                    if (attrs != null && attrs.Length > 0)
                    {
                        Stack methodStack = new Stack(); 
                        methodStack.Push(method);
 
                        bool allAttributesValid = true; 
                        foreach (RuleAttribute ruleAttr in attrs)
                        { 
                            if (!ruleAttr.Validate(validation, method, method.DeclaringType, method.GetParameters()))
                                allAttributesValid = false;
                        }
 
                        methodStack.Pop();
 
                        if (!allAttributesValid) 
                            return null;
                    } 
                }
            }

            return resultExprInfo; 
        }
 
        ///  
        /// Check that the expression is a constant, and is promotable to type ULONG.
        ///  
        /// 
        /// 
        /// 
        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] 
        private static bool PromotionPossible(Type type, CodeExpression expression)
        { 
            // C# 2.0, section 6.1.6, int/long constants can be promoted to ulong as long as in range 
            if (type == typeof(int))
            { 
                CodePrimitiveExpression primitive = expression as CodePrimitiveExpression;
                if (primitive != null)
                {
                    int i = (int)primitive.Value; 
                    return (i >= 0);
                } 
            } 
            else if (type == typeof(long))
            { 
                CodePrimitiveExpression primitive = expression as CodePrimitiveExpression;
                if (primitive != null)
                {
                    long l = (long)primitive.Value; 
                    return (l >= 0);
                } 
            } 
            return false;
        } 
        #endregion

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
        { 
            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression;
 
            // Get the method info from the validation so we can look for [RuleRead] and [RuleWrite] attributes. 
            RuleBinaryExpressionInfo expressionInfo = analysis.Validation.ExpressionInfo(binaryExpr) as RuleBinaryExpressionInfo;
            if (expressionInfo != null) 
            {
                // we may be calling a method, not a default operator
                MethodInfo method = expressionInfo.MethodInfo;
                if (method != null) 
                {
                    List attributedExprs = new List(); 
                    CodeExpressionCollection arguments = new CodeExpressionCollection(); 
                    arguments.Add(binaryExpr.Left);
                    arguments.Add(binaryExpr.Right); 
                    CodeExpression targetObject = new CodeTypeReferenceExpression(method.DeclaringType);
                    analysis.AnalyzeRuleAttributes(method, targetObject, qualifier, arguments, method.GetParameters(), attributedExprs);
                }
            } 

            // Analyze the left & right children. 
            RuleExpressionWalker.AnalyzeUsage(analysis, binaryExpr.Left, true, false, null); 
            RuleExpressionWalker.AnalyzeUsage(analysis, binaryExpr.Right, true, false, null);
        } 

        #region Evaluate
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        { 
            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression;
 
            object lhsValue = RuleExpressionWalker.Evaluate(execution, binaryExpr.Left).Value; 
            CodeBinaryOperatorType operation = binaryExpr.Operator;
            // short-circuit ANDs and ORs 
            if (operation == CodeBinaryOperatorType.BooleanAnd)
            {
                if ((bool)lhsValue)
                { 
                    // LHS is true, need to look at RHS
                    object rhsValue = RuleExpressionWalker.Evaluate(execution, binaryExpr.Right).Value; 
                    return new RuleLiteralResult(rhsValue); 
                }
                else 
                    // LHS is false, so result is false
                    return new RuleLiteralResult(false);
            }
            else if (operation == CodeBinaryOperatorType.BooleanOr) 
            {
                if ((bool)lhsValue) 
                    // LHS is true, so result is true 
                    return new RuleLiteralResult(true);
                else 
                {
                    // LHS is false, so need to look at RHS
                    object rhsValue = RuleExpressionWalker.Evaluate(execution, binaryExpr.Right).Value;
                    return new RuleLiteralResult(rhsValue); 
                }
            } 
            else 
            {
                object resultValue; 
                object rhsValue = RuleExpressionWalker.Evaluate(execution, binaryExpr.Right).Value;
                RuleBinaryExpressionInfo expressionInfo = execution.Validation.ExpressionInfo(binaryExpr) as RuleBinaryExpressionInfo;
                if (expressionInfo == null)  // Oops, someone forgot to validate.
                { 
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated);
                    InvalidOperationException exception = new InvalidOperationException(message); 
                    exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                    throw exception;
                } 
                MethodInfo methodInfo = expressionInfo.MethodInfo;
                if (methodInfo != null)
                {
                    if (methodInfo == Literal.ObjectEquality) 
                    {
                        resultValue = (lhsValue == rhsValue); 
                    } 
                    else
                    { 
                        ParameterInfo[] existingParameters = methodInfo.GetParameters();
                        object[] parameters = new object[2];
                        parameters[0] = Executor.AdjustType(expressionInfo.LeftType, lhsValue, existingParameters[0].ParameterType);
                        parameters[1] = Executor.AdjustType(expressionInfo.RightType, rhsValue, existingParameters[1].ParameterType); 
                        resultValue = methodInfo.Invoke(null, parameters);
                    } 
                } 
                else
                { 
                    resultValue = EvaluateBinaryOperation(binaryExpr, expressionInfo.LeftType, lhsValue, operation, expressionInfo.RightType, rhsValue);
                }
                return new RuleLiteralResult(resultValue);
            } 
        }
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        private static object EvaluateBinaryOperation(CodeBinaryOperatorExpression binaryExpr, Type lhsType, object lhsValue, CodeBinaryOperatorType operation, Type rhsType, object rhsValue)
        { 
            Literal leftLiteral;
            Literal rightLiteral;
            ArithmeticLiteral leftArithmetic;
            ArithmeticLiteral rightArithmetic; 
            string message;
            RuleEvaluationException exception; 
 
            switch (operation)
            { 
                case CodeBinaryOperatorType.Add:
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue);
                    if (leftArithmetic == null)
                        break; 
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue);
                    if (rightArithmetic == null) 
                        break; 
                    return leftArithmetic.Add(rightArithmetic);
                case CodeBinaryOperatorType.Subtract: 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue);
                    if (leftArithmetic == null)
                        break;
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); 
                    if (rightArithmetic == null)
                        break; 
                    return leftArithmetic.Subtract(rightArithmetic); 
                case CodeBinaryOperatorType.Multiply:
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); 
                    if (leftArithmetic == null)
                        break;
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue);
                    if (rightArithmetic == null) 
                        break;
                    return leftArithmetic.Multiply(rightArithmetic); 
                case CodeBinaryOperatorType.Divide: 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue);
                    if (leftArithmetic == null) 
                        break;
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue);
                    if (rightArithmetic == null)
                        break; 
                    return leftArithmetic.Divide(rightArithmetic);
                case CodeBinaryOperatorType.Modulus: 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); 
                    if (leftArithmetic == null)
                        break; 
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue);
                    if (rightArithmetic == null)
                        break;
                    return leftArithmetic.Modulus(rightArithmetic); 
                case CodeBinaryOperatorType.BitwiseAnd:
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue); 
                    if (leftArithmetic == null) 
                        break;
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue); 
                    if (rightArithmetic == null)
                        break;
                    return leftArithmetic.BitAnd(rightArithmetic);
                case CodeBinaryOperatorType.BitwiseOr: 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsType, lhsValue);
                    if (leftArithmetic == null) 
                        break; 
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsType, rhsValue);
                    if (rightArithmetic == null) 
                        break;
                    return leftArithmetic.BitOr(rightArithmetic);

                case CodeBinaryOperatorType.ValueEquality: 
                    leftLiteral = Literal.MakeLiteral(lhsType, lhsValue);
                    if (leftLiteral == null) 
                        break; 
                    rightLiteral = Literal.MakeLiteral(rhsType, rhsValue);
                    if (rightLiteral == null) 
                        break;
                    return leftLiteral.Equal(rightLiteral);
                case CodeBinaryOperatorType.IdentityEquality:
                    return lhsValue == rhsValue; 
                case CodeBinaryOperatorType.IdentityInequality:
                    return lhsValue != rhsValue; 
 
                case CodeBinaryOperatorType.LessThan:
                    leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); 
                    if (leftLiteral == null)
                        break;
                    rightLiteral = Literal.MakeLiteral(rhsType, rhsValue);
                    if (rightLiteral == null) 
                        break;
                    return leftLiteral.LessThan(rightLiteral); 
                case CodeBinaryOperatorType.LessThanOrEqual: 
                    leftLiteral = Literal.MakeLiteral(lhsType, lhsValue);
                    if (leftLiteral == null) 
                        break;
                    rightLiteral = Literal.MakeLiteral(rhsType, rhsValue);
                    if (rightLiteral == null)
                        break; 
                    return leftLiteral.LessThanOrEqual(rightLiteral);
                case CodeBinaryOperatorType.GreaterThan: 
                    leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); 
                    if (leftLiteral == null)
                        break; 
                    rightLiteral = Literal.MakeLiteral(rhsType, rhsValue);
                    if (rightLiteral == null)
                        break;
                    return leftLiteral.GreaterThan(rightLiteral); 
                case CodeBinaryOperatorType.GreaterThanOrEqual:
                    leftLiteral = Literal.MakeLiteral(lhsType, lhsValue); 
                    if (leftLiteral == null) 
                        break;
                    rightLiteral = Literal.MakeLiteral(rhsType, rhsValue); 
                    if (rightLiteral == null)
                        break;
                    return leftLiteral.GreaterThanOrEqual(rightLiteral);
 
                default:
                    // should never happen 
                    // BooleanAnd & BooleanOr short-circuited before call 
                    // Assign disallowed at validation time
                    message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, operation.ToString()); 
                    exception = new RuleEvaluationException(message);
                    exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr;
                    throw exception;
            } 

            message = string.Format(CultureInfo.CurrentCulture, 
                Messages.BinaryOpFails, 
                operation.ToString(),
                RuleDecompiler.DecompileType(lhsType), 
                RuleDecompiler.DecompileType(rhsType));
            exception = new RuleEvaluationException(message);
            exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr;
            throw exception; 
        }
        #endregion 
 
        #region Decompile
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            bool mustParenthesize = false; 
            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression;
 
            if (binaryExpr.Left == null) 
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.NullBinaryOpLHS, binaryExpr.Operator.ToString()); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr;
                throw exception;
            } 
            if (binaryExpr.Right == null)
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.NullBinaryOpRHS, binaryExpr.Operator.ToString()); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr; 
                throw exception;
            }

            string opString; 

            switch (binaryExpr.Operator) 
            { 
                case CodeBinaryOperatorType.Modulus:
                    opString = " % "; 
                    break;
                case CodeBinaryOperatorType.Multiply:
                    opString = " * ";
                    break; 
                case CodeBinaryOperatorType.Divide:
                    opString = " / "; 
                    break; 

                case CodeBinaryOperatorType.Subtract: 
                    opString = " - ";
                    break;
                case CodeBinaryOperatorType.Add:
                    opString = " + "; 
                    break;
 
                case CodeBinaryOperatorType.LessThan: 
                    opString = " < ";
                    break; 
                case CodeBinaryOperatorType.LessThanOrEqual:
                    opString = " <= ";
                    break;
                case CodeBinaryOperatorType.GreaterThan: 
                    opString = " > ";
                    break; 
                case CodeBinaryOperatorType.GreaterThanOrEqual: 
                    opString = " >= ";
                    break; 

                case CodeBinaryOperatorType.IdentityEquality:
                case CodeBinaryOperatorType.ValueEquality:
                    opString = " == "; 
                    break;
                case CodeBinaryOperatorType.IdentityInequality: 
                    opString = " != "; 
                    break;
 
                case CodeBinaryOperatorType.BitwiseAnd:
                    opString = " & ";
                    break;
 
                case CodeBinaryOperatorType.BitwiseOr:
                    opString = " | "; 
                    break; 

                case CodeBinaryOperatorType.BooleanAnd: 
                    opString = " && ";
                    break;

                case CodeBinaryOperatorType.BooleanOr: 
                    opString = " || ";
                    break; 
 
                default:
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, binaryExpr.Operator.ToString()); 
                    NotSupportedException exception = new NotSupportedException(message);
                    exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr;
                    throw exception;
            } 

            CodeExpression leftExpr = binaryExpr.Left; 
            CodeExpression rightExpr = binaryExpr.Right; 

 
            if (binaryExpr.Operator == CodeBinaryOperatorType.ValueEquality)
            {
                // Look for special cases:
                //    LHS == false              --> ! LHS 
                // or
                //    (LHS == expr) == false    --> LHS != expr 
 
                CodePrimitiveExpression rhsPrimitive = rightExpr as CodePrimitiveExpression;
                if (rhsPrimitive != null) 
                {
                    object rhsValue = rhsPrimitive.Value;
                    if (rhsValue != null)
                    { 
                        // we don't have the comparison "==null"
                        if (rhsValue.GetType() == typeof(bool) && (bool)rhsValue == false) 
                        { 
                            // We have comparison "== false".
 
                            CodeBinaryOperatorExpression lhsBinary = leftExpr as CodeBinaryOperatorExpression;
                            if (lhsBinary != null && lhsBinary.Operator == CodeBinaryOperatorType.ValueEquality)
                            {
                                // We have the pattern 
                                //      (expr1 == expr2) == false
                                // Treat this as: 
                                //      expr1 != expr2 

                                opString = " != "; 

                                leftExpr = lhsBinary.Left;
                                rightExpr = lhsBinary.Right;
                            } 
                            else
                            { 
                                // We have the pattern 
                                //      LHS == false
                                // Treat this as: 
                                //      ! LHS

                                mustParenthesize = RuleDecompiler.MustParenthesize(leftExpr, parentExpression);
                                if (mustParenthesize) 
                                    stringBuilder.Append("(");
 
                                // Note the "parentExpression" passed to the child decompile... cast is the only 
                                // built-in operation that has "unary" precedence, so pass that as the parent
                                // to get the parenthesization right. . 
                                stringBuilder.Append("!");
                                RuleExpressionWalker.Decompile(stringBuilder, leftExpr, new CodeCastExpression());

                                if (mustParenthesize) 
                                    stringBuilder.Append(")");
 
                                return; 
                            }
                        } 
                    }
                }
            }
            else if (binaryExpr.Operator == CodeBinaryOperatorType.Subtract) 
            {
                // Look for the special case: 
                //    0 - RHS       --> - RHS 

                CodePrimitiveExpression lhsPrimitive = leftExpr as CodePrimitiveExpression; 
                if (lhsPrimitive != null && lhsPrimitive.Value != null)
                {
                    object lhsValue = lhsPrimitive.Value;
 
                    // Check if the LHS is zero.  We'll only check a few types (decimal,
                    // double, float, int, long), since these occur most often (and the 
                    // unsigned types are all illegal). 
                    TypeCode tc = Type.GetTypeCode(lhsValue.GetType());
                    bool isZero = false; 
                    switch (tc)
                    {
                        case TypeCode.Decimal:
                            isZero = ((decimal)lhsValue) == 0; 
                            break;
 
                        case TypeCode.Double: 
                            isZero = ((double)lhsValue) == 0;
                            break; 

                        case TypeCode.Single:
                            isZero = ((float)lhsValue) == 0;
                            break; 

                        case TypeCode.Int32: 
                            isZero = ((int)lhsValue) == 0; 
                            break;
 
                        case TypeCode.Int64:
                            isZero = ((long)lhsValue) == 0;
                            break;
                    } 

                    if (isZero) 
                    { 
                        mustParenthesize = RuleDecompiler.MustParenthesize(rightExpr, parentExpression);
                        if (mustParenthesize) 
                            stringBuilder.Append("(");

                        // Note the "parentExpression" passed to the child decompile... cast is the only
                        // built-in operation that has "unary" precedence, so pass that as the parent 
                        // to get the parenthesization right.
                        stringBuilder.Append("-"); 
                        RuleExpressionWalker.Decompile(stringBuilder, rightExpr, new CodeCastExpression()); 

                        if (mustParenthesize) 
                            stringBuilder.Append(")");

                        return;
                    } 
                }
            } 
 
            mustParenthesize = RuleDecompiler.MustParenthesize(binaryExpr, parentExpression);
            if (mustParenthesize) 
                stringBuilder.Append("(");

            RuleExpressionWalker.Decompile(stringBuilder, leftExpr, binaryExpr);
            stringBuilder.Append(opString); 
            RuleExpressionWalker.Decompile(stringBuilder, rightExpr, binaryExpr);
 
            if (mustParenthesize) 
                stringBuilder.Append(")");
        } 
        #endregion

        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression;
 
            CodeBinaryOperatorExpression newOp = new CodeBinaryOperatorExpression(); 
            newOp.Operator = binaryExpr.Operator;
            newOp.Left = RuleExpressionWalker.Clone(binaryExpr.Left); 
            newOp.Right = RuleExpressionWalker.Clone(binaryExpr.Right);
            return newOp;
        }
 
        internal override bool Match(CodeExpression expression, CodeExpression comperand)
        { 
            CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression; 

            CodeBinaryOperatorExpression comperandBinary = (CodeBinaryOperatorExpression)comperand; 
            return (binaryExpr.Operator == comperandBinary.Operator
                && RuleExpressionWalker.Match(binaryExpr.Left, comperandBinary.Left)
                && RuleExpressionWalker.Match(binaryExpr.Right, comperandBinary.Right));
        } 
    }
 
    #endregion 

    #region Field ref expression 

    // CodeFieldReferenceExpression
    internal class FieldReferenceExpression : RuleExpressionInternal
    { 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            string message; 

            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression; 

            if (fieldRefExpr.TargetObject == null)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullFieldTarget, fieldRefExpr.FieldName); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                error.UserData[RuleUserDataKeys.ErrorObject] = fieldRefExpr; 
                validation.Errors.Add(error); 
                return null;
            } 

            // Early exit from this if a cycle is detected.
            if (!validation.PushParentExpression(fieldRefExpr))
                return null; 

            RuleExpressionInfo targetExprInfo = RuleExpressionWalker.Validate(validation, fieldRefExpr.TargetObject, false); 
 
            validation.PopParentExpression();
 
            if (targetExprInfo == null)		// error occurred, so simply return
                return null;

            Type targetType = targetExprInfo.ExpressionType; 
            if (targetType == null)			// no type, so must have been an error already
                return null; 
 
            if (targetType == typeof(NullLiteral))
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullFieldTarget, fieldRefExpr.FieldName);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_BindingTypeMissing);
                error.UserData[RuleUserDataKeys.ErrorObject] = fieldRefExpr;
                validation.Errors.Add(error); 
                return null;
            } 
 
            BindingFlags bindingFlags = BindingFlags.Public;
            if (fieldRefExpr.TargetObject is CodeTypeReferenceExpression) 
                bindingFlags |= BindingFlags.Static | BindingFlags.FlattenHierarchy;
            else
                bindingFlags |= BindingFlags.Instance;
            if (validation.AllowInternalMembers(targetType)) 
                bindingFlags |= BindingFlags.NonPublic;
 
            FieldInfo fi = targetType.GetField(fieldRefExpr.FieldName, bindingFlags); 
            if (fi == null)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownField, fieldRefExpr.FieldName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
                error.UserData[RuleUserDataKeys.ErrorObject] = fieldRefExpr;
                validation.Errors.Add(error); 
                return null;
            } 
 
            if (fi.FieldType == null)
            { 
                // This can only happen with a design-time type.
                message = string.Format(CultureInfo.CurrentCulture, Messages.CouldNotDetermineMemberType, fieldRefExpr.FieldName);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CouldNotDetermineMemberType);
                error.UserData[RuleUserDataKeys.ErrorObject] = fieldRefExpr; 
                validation.Errors.Add(error);
                return null; 
            } 

            if (isWritten && fi.IsLiteral) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.FieldSetNotAllowed, fieldRefExpr.FieldName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget);
                error.UserData[RuleUserDataKeys.ErrorObject] = fieldRefExpr; 
                validation.Errors.Add(error);
                return null; 
            } 

            if (!validation.ValidateMemberAccess(fieldRefExpr.TargetObject, targetType, fi, fi.Name, fieldRefExpr)) 
                return null;

                        // Is it possible to set fi by validation.ResolveFieldOrProperty(targetType, fieldExpr.FieldName)?
                        validation.IsAuthorized(fi.FieldType); 
                        return new RuleFieldExpressionInfo(fi);
        } 
 
        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
        { 
            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression;
            CodeExpression targetObject = fieldRefExpr.TargetObject;
            RuleExpressionWalker.AnalyzeUsage(analysis, targetObject, isRead, isWritten, new RulePathQualifier(fieldRefExpr.FieldName, qualifier));
        } 

        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution) 
        { 
            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression;
            object target = RuleExpressionWalker.Evaluate(execution, fieldRefExpr.TargetObject).Value; 

            RuleFieldExpressionInfo fieldExprInfo = execution.Validation.ExpressionInfo(fieldRefExpr) as RuleFieldExpressionInfo;
            if (fieldExprInfo == null)  // Oops, someone forgot to validate.
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated);
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = fieldRefExpr; 
                throw exception;
            } 

            FieldInfo fi = fieldExprInfo.FieldInfo;

            return new RuleFieldResult(target, fi); 
        }
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression) 
        {
            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression; 

            CodeExpression targetObject = fieldRefExpr.TargetObject;
            if (targetObject == null)
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.NullFieldTarget, fieldRefExpr.FieldName);
                RuleEvaluationException exception = new RuleEvaluationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = fieldRefExpr; 
                throw exception;
            } 

            RuleExpressionWalker.Decompile(stringBuilder, targetObject, fieldRefExpr);
            stringBuilder.Append('.');
            stringBuilder.Append(fieldRefExpr.FieldName); 
        }
 
        internal override CodeExpression Clone(CodeExpression expression) 
        {
            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression; 

            CodeFieldReferenceExpression newField = new CodeFieldReferenceExpression();
            newField.FieldName = fieldRefExpr.FieldName;
            newField.TargetObject = RuleExpressionWalker.Clone(fieldRefExpr.TargetObject); 
            return newField;
        } 
 
        internal override bool Match(CodeExpression expression, CodeExpression comperand)
        { 
            CodeFieldReferenceExpression fieldRefExpr = (CodeFieldReferenceExpression)expression;

            CodeFieldReferenceExpression newField = (CodeFieldReferenceExpression)comperand;
            return (fieldRefExpr.FieldName == newField.FieldName 
                && RuleExpressionWalker.Match(fieldRefExpr.TargetObject, newField.TargetObject));
        } 
    } 

    #endregion 

    #region Property ref expression

    // CodePropertyReferenceExpression 
    internal class PropertyReferenceExpression : RuleExpressionInternal
    { 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        {
            string message; 

            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression;

            if (propGetExpr.TargetObject == null) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullPropertyTarget, propGetExpr.PropertyName); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = propGetExpr;
                validation.Errors.Add(error); 
                return null;
            }

            // Early exit from this if a cycle is detected. 
            if (!validation.PushParentExpression(propGetExpr))
                return null; 
 
            RuleExpressionInfo targetExprInfo = RuleExpressionWalker.Validate(validation, propGetExpr.TargetObject, false);
 
            validation.PopParentExpression();

            if (targetExprInfo == null)		// error occurred, so simply return
                return null; 

            Type targetType = targetExprInfo.ExpressionType; 
            if (targetType == null)			// no type, so must have been an error already 
                return null;
 
            if (targetType == typeof(NullLiteral))
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullPropertyTarget, propGetExpr.PropertyName);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_BindingTypeMissing); 
                error.UserData[RuleUserDataKeys.ErrorObject] = propGetExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            bool includeNonPublic = false;
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
            if (validation.AllowInternalMembers(targetType))
            { 
                bindingFlags |= BindingFlags.NonPublic;
                includeNonPublic = true; 
            } 
                        PropertyInfo pi = validation.ResolveProperty(targetType, propGetExpr.PropertyName, bindingFlags);
 
            if (pi == null)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownProperty, propGetExpr.PropertyName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = propGetExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            if (pi.PropertyType == null)
            {
                // This can only happen with a design-time type.
                message = string.Format(CultureInfo.CurrentCulture, Messages.CouldNotDetermineMemberType, propGetExpr.PropertyName); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CouldNotDetermineMemberType);
                error.UserData[RuleUserDataKeys.ErrorObject] = propGetExpr; 
                validation.Errors.Add(error); 
                return null;
            } 

            MethodInfo accessorMethod = isWritten ? pi.GetSetMethod(includeNonPublic) : pi.GetGetMethod(includeNonPublic);
            if (accessorMethod == null)
            { 
                string baseMessage = isWritten ? Messages.UnknownPropertySet : Messages.UnknownPropertyGet;
                message = string.Format(CultureInfo.CurrentCulture, baseMessage, propGetExpr.PropertyName, RuleDecompiler.DecompileType(targetType)); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = propGetExpr;
                validation.Errors.Add(error); 
                return null;
            }

            if (!validation.ValidateMemberAccess(propGetExpr.TargetObject, targetType, accessorMethod, propGetExpr.PropertyName, propGetExpr)) 
                return null;
 
            // Validate any RuleAttributes, if present. 
            object[] attrs = pi.GetCustomAttributes(typeof(RuleAttribute), true);
            if (attrs != null && attrs.Length > 0) 
            {
                Stack methodStack = new Stack();
                methodStack.Push(pi);
 
                bool allAttributesValid = true;
                foreach (RuleAttribute ruleAttr in attrs) 
                { 
                    if (!ruleAttr.Validate(validation, pi, targetType, null))
                        allAttributesValid = false; 
                }

                methodStack.Pop();
 
                if (!allAttributesValid)
                    return null; 
            } 

            return new RulePropertyExpressionInfo(pi, pi.PropertyType, false); 
        }


        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            string message; 
 
            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression;
 
            // Evaluate the target object and get its type.
            CodeExpression targetObject = propGetExpr.TargetObject;
            RuleExpressionInfo targetExprInfo = analysis.Validation.ExpressionInfo(targetObject);
            if (targetExprInfo == null)  // Oops, someone forgot to validate. 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = targetObject;
                throw exception; 
            }

            // Get the property info from the validator so we can look for [RuleRead] and [RuleWrite] attributes.
            RulePropertyExpressionInfo propExprInfo = analysis.Validation.ExpressionInfo(propGetExpr) as RulePropertyExpressionInfo; 
            if (propExprInfo == null)  // Oops, someone forgot to validate.
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = propGetExpr; 
                throw exception;
            }

            PropertyInfo pi = propExprInfo.PropertyInfo; 

            // Look for RuleAttribute's on the invoked property. 
            List attributedExprs = new List(); 
            analysis.AnalyzeRuleAttributes(pi, targetObject, qualifier, null, null, attributedExprs);
 
            // See if the target object needs default analysis.
            if (!attributedExprs.Contains(targetObject))
            {
                // The property had no [RuleRead] or [RuleWrite] attributes.  Just qualify the target object with 
                // the property name and proceed with the analysis.
                RuleExpressionWalker.AnalyzeUsage(analysis, targetObject, isRead, isWritten, new RulePathQualifier(pi.Name, qualifier)); 
            } 
        }
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        {
            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression;
 
            object target = RuleExpressionWalker.Evaluate(execution, propGetExpr.TargetObject).Value;
 
            RulePropertyExpressionInfo propExprInfo = execution.Validation.ExpressionInfo(propGetExpr) as RulePropertyExpressionInfo; 
            if (propExprInfo == null)  // Oops, someone forgot to validate.
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated);
                InvalidOperationException exception = new InvalidOperationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = propGetExpr;
                throw exception; 
            }
 
            PropertyInfo pi = propExprInfo.PropertyInfo; 
            return new RulePropertyResult(pi, target, null);
        } 

        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression; 

            CodeExpression targetObject = propGetExpr.TargetObject; 
            if (targetObject == null) 
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.NullPropertyTarget, propGetExpr.PropertyName); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = propGetExpr;
                throw exception;
            } 

            RuleExpressionWalker.Decompile(stringBuilder, targetObject, propGetExpr); 
            stringBuilder.Append('.'); 
            stringBuilder.Append(propGetExpr.PropertyName);
        } 

        internal override CodeExpression Clone(CodeExpression expression)
        {
            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression; 

            CodePropertyReferenceExpression newProperty = new CodePropertyReferenceExpression(); 
            newProperty.PropertyName = propGetExpr.PropertyName; 
            newProperty.TargetObject = RuleExpressionWalker.Clone(propGetExpr.TargetObject);
            return newProperty; 
        }

        internal override bool Match(CodeExpression expression, CodeExpression comperand)
        { 
            CodePropertyReferenceExpression propGetExpr = (CodePropertyReferenceExpression)expression;
 
            CodePropertyReferenceExpression newProperty = (CodePropertyReferenceExpression)comperand; 
            return (propGetExpr.PropertyName == newProperty.PropertyName
                && RuleExpressionWalker.Match(propGetExpr.TargetObject, newProperty.TargetObject)); 
        }
    }

    #endregion 

    #region Method invoke expression 
 
    // CodeMethodInvokeExpression
    internal class MethodInvokeExpression : RuleExpressionInternal 
    {
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            Type targetType = null;
            RuleMethodInvokeExpressionInfo methodInvokeInfo = null; 
            string message; 
            ValidationError error = null;
            BindingFlags bindingFlags = BindingFlags.Public; 

            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression;

            if (isWritten) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeMethodInvokeExpression).ToString()); 
                error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr;
                validation.Errors.Add(error); 
                return null;
            }

            if ((invokeExpr.Method == null) || (invokeExpr.Method.TargetObject == null)) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullMethodTarget, invokeExpr.Method.MethodName); 
                error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr;
                validation.Errors.Add(error); 
                return null; // Fatal error; discontinue validation of this object.
            }

            if ((invokeExpr.Method.TypeArguments != null) && (invokeExpr.Method.TypeArguments.Count > 0)) 
            {
                error = new ValidationError(Messages.GenericMethodsNotSupported, ErrorNumbers.Error_CodeExpressionNotHandled); 
                error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr; 
                validation.Errors.Add(error);
                return null; 
            }

            try
            { 
                // Early exit from this if a cycle is detected.
                if (!validation.PushParentExpression(invokeExpr)) 
                    return null; 

                RuleExpressionInfo targetExprInfo = RuleExpressionWalker.Validate(validation, invokeExpr.Method.TargetObject, false); 
                if (targetExprInfo == null)		// error occurred, so simply return
                    return null;

                targetType = targetExprInfo.ExpressionType; 
                if (targetType == null)
                    return null; 
 
                // if an error occurred (targetType == null), continue on to validate the arguments
                if (targetType == typeof(NullLiteral)) 
                {
                    message = string.Format(CultureInfo.CurrentCulture, Messages.NullMethodTarget, invokeExpr.Method.MethodName);
                    error = new ValidationError(message, ErrorNumbers.Error_BindingTypeMissing);
                    error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr; 
                    validation.Errors.Add(error);
                    targetType = null; // force exit after validating the arguments 
                } 

                List argExprs = new List(); 

                bool hasInvalidArgument = false;
                if (invokeExpr.Parameters != null)
                { 
                    for (int i = 0; i < invokeExpr.Parameters.Count; ++i)
                    { 
                        CodeExpression argExpr = invokeExpr.Parameters[i]; 
                        if (argExpr == null)
                        { 
                            message = string.Format(CultureInfo.CurrentCulture, Messages.NullMethodParameter, i.ToString(CultureInfo.CurrentCulture), invokeExpr.Method.MethodName);
                            error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                            error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr;
                            validation.Errors.Add(error); 
                            targetType = null; // force exit after validating the rest of the arguments
                        } 
                        else 
                        {
                            if (argExpr is CodeTypeReferenceExpression) 
                            {
                                message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, argExpr.GetType().FullName);
                                error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                                error.UserData[RuleUserDataKeys.ErrorObject] = argExpr; 
                                validation.AddError(error);
 
                                hasInvalidArgument = true; 
                            }
 
                            // Validate the argument.
                            RuleExpressionInfo argExprInfo = RuleExpressionWalker.Validate(validation, argExpr, false);
                            if (argExprInfo == null)
                                hasInvalidArgument = true; 
                            argExprs.Add(argExpr);
                        } 
                    } 
                }
 
                // Stop further validation if there was a problem with the target expression.
                if (targetType == null)
                    return null;
 
                // Stop further validation if there was a problem with any of the arguments.
                if (hasInvalidArgument) 
                    return null; 

                if (invokeExpr.Method.TargetObject is CodeTypeReferenceExpression) 
                    bindingFlags |= BindingFlags.Static | BindingFlags.FlattenHierarchy;
                else
                    bindingFlags |= BindingFlags.Instance;
                if (validation.AllowInternalMembers(targetType)) 
                    bindingFlags |= BindingFlags.NonPublic;
 
                // Everything okay so far, try to resolve the method. 
                methodInvokeInfo = validation.ResolveMethod(targetType, invokeExpr.Method.MethodName, bindingFlags, argExprs, out error);
                if ((methodInvokeInfo == null) && (invokeExpr.UserData.Contains(RuleUserDataKeys.QualifiedName))) 
                {
                    // failed to resolve the method, but a fully qualified type name is around
                    // load the type, add it to the assemblies, and try again
                    string qualifiedName = invokeExpr.UserData[RuleUserDataKeys.QualifiedName] as string; 
                    Type containingClassType = validation.ResolveType(qualifiedName);
                    if (containingClassType != null) 
                    { 
                        validation.DetermineExtensionMethods(containingClassType.Assembly);
                        methodInvokeInfo = validation.ResolveMethod(targetType, invokeExpr.Method.MethodName, bindingFlags, argExprs, out error); 
                    }
                }
                if (methodInvokeInfo == null)
                { 
                    error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr;
                    validation.Errors.Add(error); 
                    return null; 
                }
            } 
            finally
            {
                validation.PopParentExpression();
            } 

 
            MethodInfo mi = methodInvokeInfo.MethodInfo; 

            if (mi.ReturnType == null) 
            {
                // This can only happen with a design-time type.
                message = string.Format(CultureInfo.CurrentCulture, Messages.CouldNotDetermineMemberType, invokeExpr.Method.MethodName);
                error = new ValidationError(message, ErrorNumbers.Error_CouldNotDetermineMemberType); 
                error.UserData[RuleUserDataKeys.ErrorObject] = invokeExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            if (!validation.ValidateMemberAccess(invokeExpr.Method.TargetObject, targetType, mi, invokeExpr.Method.MethodName, invokeExpr))
                return null;

            // Validate any RuleAttributes, if present. 
            object[] attrs = mi.GetCustomAttributes(typeof(RuleAttribute), true);
            if (attrs != null && attrs.Length > 0) 
            { 
                Stack methodStack = new Stack();
                methodStack.Push(mi); 

                bool allAttributesValid = true;
                foreach (RuleAttribute ruleAttr in attrs)
                { 
                    if (!ruleAttr.Validate(validation, mi, targetType, mi.GetParameters()))
                        allAttributesValid = false; 
                } 

                methodStack.Pop(); 

                if (!allAttributesValid)
                    return null;
            } 

            // if this is an extension method, save the type information 
            if (mi is ExtensionMethodInfo) 
            {
                invokeExpr.UserData[RuleUserDataKeys.QualifiedName] = mi.DeclaringType.AssemblyQualifiedName; 
            }

            return methodInvokeInfo;
        } 

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        { 
            string message;
 
            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression;

            // Get the target object's type.
            CodeExpression targetObject = invokeExpr.Method.TargetObject; 
            RuleExpressionInfo targetExprInfo = analysis.Validation.ExpressionInfo(targetObject);
            if (targetExprInfo == null)  // Oops, someone forgot to validate. 
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated);
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = targetObject;
                throw exception;
            }
 
            // Get the method info from the validation so we can look for [RuleRead] and [RuleWrite] attributes.
            RuleMethodInvokeExpressionInfo methodExprInfo = analysis.Validation.ExpressionInfo(invokeExpr) as RuleMethodInvokeExpressionInfo; 
            if (methodExprInfo == null)  // Oops, someone forgot to validate. 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = invokeExpr;
                throw exception;
            } 

            MethodInfo mi = methodExprInfo.MethodInfo; 
 
            // Look for RuleAttribute's on the invoked method.
            List attributedExprs = new List(); 
            analysis.AnalyzeRuleAttributes(mi, targetObject, qualifier, invokeExpr.Parameters, mi.GetParameters(), attributedExprs);

            // See if the target object needs default analysis.
            if (!attributedExprs.Contains(targetObject)) 
            {
                // No applicable [RuleRead] or [RuleWrite] attributes were found on the target object. 
 
                // If we're analyzing for dependencies, assume that this method uses the
                // value of the target object, but nothing beneath it. 

                RuleExpressionWalker.AnalyzeUsage(analysis, targetObject, true, false, null);
            }
 
            // See if any of the arguments need default analysis.
            for (int i = 0; i < invokeExpr.Parameters.Count; ++i) 
            { 
                CodeExpression argExpr = invokeExpr.Parameters[i];
 
                if (!attributedExprs.Contains(argExpr))
                {
                    // Similar to the target object, we assume that this method can reads the value
                    // of the parameter, but none of its members. 
                    RuleExpressionWalker.AnalyzeUsage(analysis, argExpr, true, false, null);
                } 
            } 
        }
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        {
            string message;
 
            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression;
 
            object target = RuleExpressionWalker.Evaluate(execution, invokeExpr.Method.TargetObject).Value; 

            RuleMethodInvokeExpressionInfo invokeExprInfo = execution.Validation.ExpressionInfo(invokeExpr) as RuleMethodInvokeExpressionInfo; 
            if (invokeExprInfo == null)  // Oops, someone forgot to validate.
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated);
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = invokeExpr;
                throw exception; 
            } 

            MethodInfo mi = invokeExprInfo.MethodInfo; 

            if (!mi.IsStatic && target == null)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.TargetEvaluatedNullMethod, invokeExpr.Method.MethodName); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = invokeExpr; 
                throw exception; 
            }
 
            object[] arguments = null;
            RuleExpressionResult[] outArgumentResults = null;

            if (invokeExpr.Parameters != null && invokeExpr.Parameters.Count > 0) 
            {
                int actualArgCount = invokeExpr.Parameters.Count; 
 
                ParameterInfo[] parmInfos = mi.GetParameters();
 
                arguments = new object[parmInfos.Length];

                int numFixedParameters = parmInfos.Length;
                if (invokeExprInfo.NeedsParamsExpansion) 
                    numFixedParameters -= 1;
 
                int i; 

                // Evaluate the fixed portion of the parameter list. 
                for (i = 0; i < numFixedParameters; ++i)
                {
                    Type argType = execution.Validation.ExpressionInfo(invokeExpr.Parameters[i]).ExpressionType;
                    RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, invokeExpr.Parameters[i]); 

                    // Special procesing of direction expressions to keep track of out arguments (& ref). 
                    CodeDirectionExpression direction = invokeExpr.Parameters[i] as CodeDirectionExpression; 
                    if (direction != null && (direction.Direction == FieldDirection.Ref || direction.Direction == FieldDirection.Out))
                    { 
                        // lazy creation of fieldsToSet
                        if (outArgumentResults == null)
                            outArgumentResults = new RuleExpressionResult[invokeExpr.Parameters.Count];
                        // keep track of this out expression so we can set it later 
                        outArgumentResults[i] = argResult;
 
                        // don't evaluate out arguments 
                        if (direction.Direction != FieldDirection.Out)
                            arguments[i] = Executor.AdjustType(argType, argResult.Value, parmInfos[i].ParameterType); 
                    }
                    else
                    {
                        // treat as in 
                        arguments[i] = Executor.AdjustType(argType, argResult.Value, parmInfos[i].ParameterType);
                    } 
                } 

                if (numFixedParameters < actualArgCount) 
                {
                    // This target method had a params array, and we are calling it with an
                    // expanded parameter list.  E.g.,
                    //      void foo(int x, params string[] y) 
                    // with the invocation:
                    //      foo(5, "crud", "kreeble", "glorp") 
                    // We need to translate this to: 
                    //      foo(5, new string[] { "crud", "kreeble", "glorp" })
 
                    ParameterInfo lastParamInfo = parmInfos[numFixedParameters];

                    Type arrayType = lastParamInfo.ParameterType;
                    System.Diagnostics.Debug.Assert(arrayType.IsArray); 
                    Type elementType = arrayType.GetElementType();
 
                    Array paramsArray = (Array)arrayType.InvokeMember(arrayType.Name, BindingFlags.CreateInstance, null, null, new object[] { actualArgCount - i }, CultureInfo.CurrentCulture); 
                    for (; i < actualArgCount; ++i)
                    { 
                        Type argType = execution.Validation.ExpressionInfo(invokeExpr.Parameters[i]).ExpressionType;
                        RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, invokeExpr.Parameters[i]);
                        paramsArray.SetValue(Executor.AdjustType(argType, argResult.Value, elementType), i - numFixedParameters);
                    } 

                    arguments[numFixedParameters] = paramsArray; 
                } 
            }
 
            object result;
            try
            {
                result = mi.Invoke(target, arguments); 
            }
            catch (TargetInvocationException e) 
            { 
                // if there is no inner exception, leave it untouched
                if (e.InnerException == null) 
                    throw;
                message = string.Format(CultureInfo.CurrentCulture, Messages.Error_MethodInvoke,
                    RuleDecompiler.DecompileType(mi.ReflectedType), mi.Name, e.InnerException.Message);
                throw new TargetInvocationException(message, e.InnerException); 
            }
 
            // any out/ref parameters that need to be assigned? 
            if (outArgumentResults != null)
            { 
                for (int i = 0; i < invokeExpr.Parameters.Count; ++i)
                {
                    if (outArgumentResults[i] != null)
                        outArgumentResults[i].Value = arguments[i]; 
                }
            } 
 
            return new RuleLiteralResult(result);
        } 

        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression; 

            if ((invokeExpr.Method == null) || (invokeExpr.Method.TargetObject == null)) 
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.NullMethodTarget, invokeExpr.Method.MethodName);
                RuleEvaluationException exception = new RuleEvaluationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = invokeExpr;
                throw exception;
            }
 
            // Decompile the target expression.
            CodeExpression targetObject = invokeExpr.Method.TargetObject; 
            RuleExpressionWalker.Decompile(stringBuilder, targetObject, invokeExpr); 

            stringBuilder.Append('.'); 
            stringBuilder.Append(invokeExpr.Method.MethodName);

            // Decompile the arguments
            stringBuilder.Append('('); 

            if (invokeExpr.Parameters != null) 
            { 
                for (int i = 0; i < invokeExpr.Parameters.Count; ++i)
                { 
                    CodeExpression paramExpr = invokeExpr.Parameters[i];
                    if (paramExpr == null)
                    {
                        string message = string.Format(CultureInfo.CurrentCulture, Messages.NullMethodTypeParameter, i.ToString(CultureInfo.CurrentCulture), invokeExpr.Method.MethodName); 
                        RuleEvaluationException exception = new RuleEvaluationException(message);
                        exception.Data[RuleUserDataKeys.ErrorObject] = invokeExpr; 
                        throw exception; 
                    }
 
                    if (i > 0)
                        stringBuilder.Append(", ");

                    RuleExpressionWalker.Decompile(stringBuilder, paramExpr, null); 
                }
            } 
 
            stringBuilder.Append(')');
        } 

        internal override CodeExpression Clone(CodeExpression expression)
        {
            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression; 

            CodeMethodInvokeExpression newMethod = new CodeMethodInvokeExpression(); 
            newMethod.Method = CloneMethodReference(invokeExpr.Method); 
            foreach (CodeExpression argument in invokeExpr.Parameters)
                newMethod.Parameters.Add(RuleExpressionWalker.Clone(argument)); 
            return newMethod;
        }

        private static CodeMethodReferenceExpression CloneMethodReference(CodeMethodReferenceExpression oldReference) 
        {
            CodeMethodReferenceExpression newReference = new CodeMethodReferenceExpression(); 
            newReference.MethodName = oldReference.MethodName; 
            newReference.TargetObject = RuleExpressionWalker.Clone(oldReference.TargetObject);
            foreach (CodeTypeReference typeReference in oldReference.TypeArguments) 
                newReference.TypeArguments.Add(TypeReferenceExpression.CloneType(typeReference));
            ConditionHelper.CloneUserData(oldReference, newReference);
            return newReference;
        } 

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        { 
            CodeMethodInvokeExpression invokeExpr = (CodeMethodInvokeExpression)expression;
 
            CodeMethodInvokeExpression newMethod = (CodeMethodInvokeExpression)comperand;
            if (invokeExpr.Method.MethodName != newMethod.Method.MethodName)
                return false;
            if (!RuleExpressionWalker.Match(invokeExpr.Method.TargetObject, newMethod.Method.TargetObject)) 
                return false;
            if (invokeExpr.Parameters.Count != newMethod.Parameters.Count) 
                return false; 
            for (int i = 0; i < invokeExpr.Parameters.Count; ++i)
            { 
                if (!RuleExpressionWalker.Match(invokeExpr.Parameters[i], newMethod.Parameters[i]))
                    return false;
            }
            return true; 
        }
    } 
 
    #endregion
 
    #region Direction expression (in/out/ref)

    // CodeDirectionExpression
    internal class DirectionExpression : RuleExpressionInternal 
    {
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        { 
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression;
 
            if (isWritten)
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeDirectionExpression).ToString());
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = directionExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            // direction specified, make sure that something is specified
            if (directionExpr.Expression == null)
            {
                ValidationError error = new ValidationError(Messages.NullDirectionTarget, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = directionExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            if (directionExpr.Expression is CodeTypeReferenceExpression)
            {
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, directionExpr.Expression.GetType().FullName);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled); 
                error.UserData[RuleUserDataKeys.ErrorObject] = directionExpr.Expression;
                validation.AddError(error); 
                return null; 
            }
 
            // validate the parameter
            RuleExpressionInfo paramExprInfo;
            bool isRef;
            if (directionExpr.Direction == FieldDirection.Ref) 
            {
                // ref parameters require that we both read and write the value 
                isRef = true; 
                paramExprInfo = RuleExpressionWalker.Validate(validation, directionExpr.Expression, false);
                if (paramExprInfo == null) 
                    return null;
                paramExprInfo = RuleExpressionWalker.Validate(validation, directionExpr.Expression, true);
            }
            else if (directionExpr.Direction == FieldDirection.Out) 
            {
                // out parameters mean that we only write to it 
                isRef = true; 
                paramExprInfo = RuleExpressionWalker.Validate(validation, directionExpr.Expression, true);
            } 
            else
            {
                // other parameters are treated as in, so we need to be able to read them
                isRef = false; 
                paramExprInfo = RuleExpressionWalker.Validate(validation, directionExpr.Expression, false);
            } 
            if (paramExprInfo == null) 
                return null;
 
            // determine it's type
            Type parameterType = paramExprInfo.ExpressionType;
            if (parameterType == null)
                return null; 

            if (parameterType != typeof(NullLiteral)) 
            { 
                // adjust type if necessary
                if (isRef && !parameterType.IsByRef) 
                    parameterType = parameterType.MakeByRefType();
            }
            return new RuleExpressionInfo(parameterType);
        } 

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        { 
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression;
            CodeExpression paramExpr = directionExpr.Expression; 

            bool argIsWritten = false;
            bool argIsRead = true;
            RulePathQualifier argQualifier = null; 
            switch (directionExpr.Direction)
            { 
                case FieldDirection.In: 
                    // We assume that all children (* suffix) of this argument can be read.
                    argIsWritten = false; 
                    argIsRead = true;
                    argQualifier = new RulePathQualifier("*", null);
                    break;
 
                case FieldDirection.Ref:
                    // When this happens in a condition, we treat this like an "in" (above): all 
                    // children (* suffix) of this argument are read.  When this happens in an 
                    // action, we treat this like an "out" (below):  we assume this argument is
                    // modified (no suffix). 
                    argIsWritten = true;
                    argIsRead = true;
                    argQualifier = analysis.ForWrites ? null : new RulePathQualifier("*", null);
                    break; 

                case FieldDirection.Out: 
                    // We assume that this argument is modified (no suffix). 
                    argIsWritten = true;
                    argIsRead = false; 
                    argQualifier = null;
                    break;
            }
 
            RuleExpressionWalker.AnalyzeUsage(analysis, paramExpr, argIsRead, argIsWritten, argQualifier);
        } 
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        { 
            // For evaluation purposes, ignore the direction.  It is handled specifically in the
            // method invoke Evaluate method.
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression;
            return RuleExpressionWalker.Evaluate(execution, directionExpr.Expression); 
        }
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression) 
        {
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression; 

            string direction = null;
            if (directionExpr.Direction == FieldDirection.Out)
                direction = "out "; 
            else if (directionExpr.Direction == FieldDirection.Ref)
                direction = "ref "; 
 
            if (direction != null)
                stringBuilder.Append(direction); 

            RuleExpressionWalker.Decompile(stringBuilder, directionExpr.Expression, directionExpr);
        }
 
        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression; 
            CodeDirectionExpression newDirection = new CodeDirectionExpression();
            newDirection.Direction = directionExpr.Direction; 
            newDirection.Expression = RuleExpressionWalker.Clone(directionExpr.Expression);
            return newDirection;
        }
 
        internal override bool Match(CodeExpression expression, CodeExpression comperand)
        { 
            CodeDirectionExpression directionExpr = (CodeDirectionExpression)expression; 
            CodeDirectionExpression newDirection = (CodeDirectionExpression)comperand;
            return (directionExpr.Direction == newDirection.Direction && 
                RuleExpressionWalker.Match(directionExpr.Expression, newDirection.Expression));
        }
    }
 
    #endregion
 
    #region Type Reference expression 

    // CodeTypeReferenceExpression 
    internal class TypeReferenceExpression : RuleExpressionInternal
    {
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            CodeTypeReferenceExpression typeRefExpr = (CodeTypeReferenceExpression)expression;
 
            if (typeRefExpr.Type == null) 
            {
                ValidationError error = new ValidationError(Messages.NullTypeType, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = typeRefExpr;
                validation.Errors.Add(error);
                return null;
            } 

            if (isWritten) 
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeTypeReferenceExpression).ToString());
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = typeRefExpr;
                validation.Errors.Add(error);
                return null;
            } 

            Type resultType = validation.ResolveType(typeRefExpr.Type); 
 
            return new RuleExpressionInfo(resultType);
        } 

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
        {
            // These introduce no interesting dependencies or side-effects. 
        }
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution) 
        {
            // Type references don't evaluate to any value. 
            return new RuleLiteralResult(null);
        }

        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression) 
        {
            CodeTypeReferenceExpression typeRefExpr = (CodeTypeReferenceExpression)expression; 
            RuleDecompiler.DecompileType(stringBuilder, typeRefExpr.Type); 
        }
 
        internal override CodeExpression Clone(CodeExpression expression)
        {
            CodeTypeReferenceExpression typeRefExpr = (CodeTypeReferenceExpression)expression;
            CodeTypeReferenceExpression newType = new CodeTypeReferenceExpression(CloneType(typeRefExpr.Type)); 
            return newType;
        } 
 
        static internal CodeTypeReference CloneType(CodeTypeReference oldType)
        { 
            if (oldType == null)
                return null;

            CodeTypeReference newType = new CodeTypeReference(); 
            newType.ArrayElementType = CloneType(oldType.ArrayElementType);
            newType.ArrayRank = oldType.ArrayRank; 
            newType.BaseType = oldType.BaseType; 
            foreach (CodeTypeReference typeReference in oldType.TypeArguments)
                newType.TypeArguments.Add(CloneType(typeReference)); 

            ConditionHelper.CloneUserData(oldType, newType);

            return newType; 
        }
 
        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeTypeReferenceExpression typeRefExpr = (CodeTypeReferenceExpression)expression; 
            CodeTypeReferenceExpression newType = (CodeTypeReferenceExpression)comperand;
            return MatchType(typeRefExpr.Type, newType.Type);
        }
 
        static internal bool MatchType(CodeTypeReference typeRef1, CodeTypeReference typeRef2)
        { 
            if (typeRef1.BaseType != typeRef2.BaseType) 
                return false;
 
            if (typeRef1.TypeArguments.Count != typeRef2.TypeArguments.Count)
                return false;
            for (int i = 0; i < typeRef1.TypeArguments.Count; ++i)
            { 
                CodeTypeReference trArg1 = typeRef1.TypeArguments[i];
                CodeTypeReference trArg2 = typeRef2.TypeArguments[i]; 
 
                if (!MatchType(trArg1, trArg2))
                    return false; 
            }

            return true;
        } 
    }
 
    #endregion 

    #region Cast expression 

    // CodeCastExpression
    internal class CastExpression : RuleExpressionInternal
    { 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        { 
            string message;
 
            CodeCastExpression castExpr = (CodeCastExpression)expression;

            if (isWritten)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeCastExpression).ToString());
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = castExpr; 
                validation.Errors.Add(error);
                return null; 
            }

            if (castExpr.Expression == null)
            { 
                ValidationError error = new ValidationError(Messages.NullCastExpr, ErrorNumbers.Error_ParameterNotSet);
                error.UserData[RuleUserDataKeys.ErrorObject] = castExpr; 
                validation.Errors.Add(error); 
                return null;
            } 

            if (castExpr.Expression is CodeTypeReferenceExpression)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, castExpr.Expression.GetType().FullName); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                error.UserData[RuleUserDataKeys.ErrorObject] = castExpr.Expression; 
                validation.AddError(error); 
                return null;
            } 

            if (castExpr.TargetType == null)
            {
                ValidationError error = new ValidationError(Messages.NullCastType, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = castExpr;
                validation.Errors.Add(error); 
                return null; 
            }
 
            // Figure out the operand type.
            RuleExpressionInfo operandInfo = RuleExpressionWalker.Validate(validation, castExpr.Expression, false);
            if (operandInfo == null)
                return null; 
            Type fromType = operandInfo.ExpressionType;
 
            Type toType = validation.ResolveType(castExpr.TargetType); 
            if (toType == null)
                return null; 

            if (fromType == typeof(NullLiteral))
            {
                // Casting from null value. 
                if (ConditionHelper.IsNonNullableValueType(toType))
                { 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CastOfNullInvalid, RuleDecompiler.DecompileType(toType)); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                    error.UserData[RuleUserDataKeys.ErrorObject] = castExpr; 
                    validation.Errors.Add(error);
                    return null;
                }
            } 
            else
            { 
                // Unwrap nullables to make life easy. 
                Type fromType2 = fromType;
                if (ConditionHelper.IsNullableValueType(fromType2)) 
                    fromType2 = fromType2.GetGenericArguments()[0];

                Type toType2 = toType;
                if (ConditionHelper.IsNullableValueType(toType2)) 
                    toType2 = toType2.GetGenericArguments()[0];
 
                bool canConvert = false; 
                if (fromType2.IsValueType && toType2.IsValueType)
                { 
                    // Convert.ChangeType doesn't handle enum <--> numeric
                    // and float/double/decimal <--> char, which are allowed
                    if (fromType2.IsEnum)
                    { 
                        canConvert = (toType2.IsEnum) || IsNumeric(toType2);
                    } 
                    else if (toType2.IsEnum) 
                    {
                        // don't need to check fromType for enum since it's handled above 
                        canConvert = IsNumeric(fromType2);
                    }
                    else if (fromType2 == typeof(char))
                    { 
                        canConvert = IsNumeric(toType2);
                    } 
                    else if (toType2 == typeof(char)) 
                    {
                        canConvert = IsNumeric(fromType2); 
                    }
                    else if (fromType2.IsPrimitive && toType2.IsPrimitive)
                    {
                        try 
                        {
                            // note: this also allows bool <--> numeric conversions 
                            object fromValueDefault = Activator.CreateInstance(fromType2); 
                            Convert.ChangeType(fromValueDefault, toType2, CultureInfo.CurrentCulture);
                            canConvert = true; 
                        }
                        catch (Exception)
                        {
                            canConvert = false; 
                        }
                    } 
                } 

                if (!canConvert) 
                {
                    // We can cast up or down an inheritence hierarchy,
                    // as well as support explicit and implicit overrides
                    ValidationError error; 
                    canConvert = RuleValidation.ExplicitConversionSpecified(fromType, toType, out error);
                    if (error != null) 
                    { 
                        error.UserData[RuleUserDataKeys.ErrorObject] = castExpr;
                        validation.Errors.Add(error); 
                        return null;
                    }
                }
 
                if (!canConvert)
                { 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CastIncompatibleTypes, RuleDecompiler.DecompileType(fromType), RuleDecompiler.DecompileType(toType)); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                    error.UserData[RuleUserDataKeys.ErrorObject] = castExpr; 
                    validation.Errors.Add(error);
                    return null;
                }
            } 

            return new RuleExpressionInfo(toType); 
        } 

        private static bool IsNumeric(Type type) 
        {
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.SByte: 
                case TypeCode.Byte:
                case TypeCode.Int16: 
                case TypeCode.UInt16: 
                case TypeCode.Int32:
                case TypeCode.UInt32: 
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.Char:
                case TypeCode.Single: 
                case TypeCode.Double:
                case TypeCode.Decimal: 
                    return true; 
                default:
                    return false; 
            }
        }

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            // Just analyze the child. 
            CodeCastExpression castExpr = (CodeCastExpression)expression; 
            RuleExpressionWalker.AnalyzeUsage(analysis, castExpr.Expression, true, false, null);
        } 

        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        {
            string message; 

            CodeCastExpression castExpr = (CodeCastExpression)expression; 
 
            // Evaluate the operand.
            object operandValue = RuleExpressionWalker.Evaluate(execution, castExpr.Expression).Value; 

            // Get the cast-to type.
            RuleExpressionInfo castExprInfo = execution.Validation.ExpressionInfo(castExpr);
            if (castExprInfo == null)  // Oops, someone forgot to validate. 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = castExpr;
                throw exception; 
            }
            Type toType = castExprInfo.ExpressionType;

            // Handle null operand result. 
            if (operandValue == null)
            { 
                // Here we are casting null to something. If it is a value type we can't do it. 
                if (ConditionHelper.IsNonNullableValueType(toType))
                { 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CastIncompatibleTypes, Messages.NullValue, RuleDecompiler.DecompileType(toType));
                    RuleEvaluationException exception = new RuleEvaluationException(message);
                    exception.Data[RuleUserDataKeys.ErrorObject] = castExpr;
                    throw exception; 
                }
                // If it's not a value type, null is good. 
            } 
            else
            { 
                Type operandType = execution.Validation.ExpressionInfo(castExpr.Expression).ExpressionType;
                operandValue = Executor.AdjustTypeWithCast(operandType, operandValue, toType);
            }
 
            return new RuleLiteralResult(operandValue);
        } 
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        { 
            CodeCastExpression castExpr = (CodeCastExpression)expression;

            CodeExpression targetObject = castExpr.Expression;
            if (targetObject == null) 
            {
                RuleEvaluationException exception = new RuleEvaluationException(Messages.NullCastExpr); 
                exception.Data[RuleUserDataKeys.ErrorObject] = castExpr; 
                throw exception;
            } 

            if (castExpr.TargetType == null)
            {
                RuleEvaluationException exception = new RuleEvaluationException(Messages.NullCastType); 
                exception.Data[RuleUserDataKeys.ErrorObject] = castExpr;
                throw exception; 
            } 

            bool mustParenthesize = RuleDecompiler.MustParenthesize(castExpr, parentExpression); 
            if (mustParenthesize)
                stringBuilder.Append("(");

            stringBuilder.Append("("); 
            RuleDecompiler.DecompileType(stringBuilder, castExpr.TargetType);
            stringBuilder.Append(")"); 
            RuleExpressionWalker.Decompile(stringBuilder, targetObject, castExpr); 

            if (mustParenthesize) 
                stringBuilder.Append(")");
        }

        internal override CodeExpression Clone(CodeExpression expression) 
        {
            CodeCastExpression castExpr = (CodeCastExpression)expression; 
            CodeCastExpression newCast = new CodeCastExpression(); 
            newCast.TargetType = TypeReferenceExpression.CloneType(castExpr.TargetType);
            newCast.Expression = RuleExpressionWalker.Clone(castExpr.Expression); 
            return newCast;
        }

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeCastExpression castExpr = (CodeCastExpression)expression; 
            CodeCastExpression castComperand = (CodeCastExpression)comperand; 

            return TypeReferenceExpression.MatchType(castExpr.TargetType, castComperand.TargetType) && 
                RuleExpressionWalker.Match(castExpr.Expression, castComperand.Expression);
        }
    }
 
    #endregion
 
    #region Indexer Expression (indexer properties) 

    // CodeIndexerExpression 
    internal class IndexerPropertyExpression : RuleExpressionInternal
    {
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        {
            string message; 
            ValidationError error = null; 
            RulePropertyExpressionInfo propExprInfo = null;
            bool includeNonPublic = false; 
            Type targetType = null;

            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression;
 
            CodeExpression targetObject = indexerExpr.TargetObject;
            if (targetObject == null) 
            { 
                error = new ValidationError(Messages.NullIndexerTarget, ErrorNumbers.Error_ParameterNotSet);
                error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr; 
                validation.Errors.Add(error);
                return null;
            }
 
            if (targetObject is CodeTypeReferenceExpression)
            { 
                error = new ValidationError(Messages.IndexersCannotBeStatic, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr;
                validation.Errors.Add(error); 
                return null;
            }

            if (indexerExpr.Indices == null || indexerExpr.Indices.Count == 0) 
            {
                error = new ValidationError(Messages.MissingIndexExpressions, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr; 
                validation.Errors.Add(error);
                return null; 
            }

            try
            { 
                // Early exit from this if a cycle is detected.
                if (!validation.PushParentExpression(indexerExpr)) 
                    return null; 

                RuleExpressionInfo targetExprInfo = RuleExpressionWalker.Validate(validation, indexerExpr.TargetObject, false); 
                if (targetExprInfo == null)		// error occurred, so simply return
                    return null;

                targetType = targetExprInfo.ExpressionType; 
                if (targetType == null)
                    return null; 
 
                // if an error occurred (targetType == null), continue on to validate the arguments
                if (targetType == typeof(NullLiteral)) 
                {
                    message = string.Format(CultureInfo.CurrentCulture, Messages.NullIndexerTarget);
                    error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                    error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr; 
                    validation.Errors.Add(error);
                    targetType = null; // force exit after validating the arguments 
                } 

                List argExprs = new List(); 

                bool hasInvalidArgument = false;
                for (int i = 0; i < indexerExpr.Indices.Count; ++i)
                { 
                    CodeExpression argExpr = indexerExpr.Indices[i];
                    if (argExpr == null) 
                    { 
                        error = new ValidationError(Messages.NullIndexExpression, ErrorNumbers.Error_ParameterNotSet);
                        error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr; 
                        validation.Errors.Add(error);
                        hasInvalidArgument = true;
                    }
                    else 
                    {
                        CodeDirectionExpression argDirection = argExpr as CodeDirectionExpression; 
                        if (argDirection != null && argDirection.Direction != FieldDirection.In) 
                        {
                            // No "ref" or "out" arguments are allowed on indexer arguments. 
                            error = new ValidationError(Messages.IndexerArgCannotBeRefOrOut, ErrorNumbers.Error_IndexerArgCannotBeRefOrOut);
                            error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr;
                            validation.Errors.Add(error);
                            hasInvalidArgument = true; 
                        }
 
                        if (argExpr is CodeTypeReferenceExpression) 
                        {
                            message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, argExpr.GetType().FullName); 
                            error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                            error.UserData[RuleUserDataKeys.ErrorObject] = argExpr;
                            validation.AddError(error);
                            hasInvalidArgument = true; 
                        }
 
                        // Validate the argument. 
                        RuleExpressionInfo argExprInfo = RuleExpressionWalker.Validate(validation, argExpr, false);
                        if (argExprInfo == null) 
                            hasInvalidArgument = true;
                        else
                            argExprs.Add(argExpr);
                    } 
                }
 
                // Stop further validation if there was a problem with the target expression. 
                if (targetType == null)
                    return null; 

                // Stop further validation if there was a problem with any of the arguments.
                if (hasInvalidArgument)
                    return null; 

                BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; 
                if (validation.AllowInternalMembers(targetType)) 
                {
                    bindingFlags |= BindingFlags.NonPublic; 
                    includeNonPublic = true;
                }

                // Everything okay so far, try to resolve the method. 
                propExprInfo = validation.ResolveIndexerProperty(targetType, bindingFlags, argExprs, out error);
                if (propExprInfo == null) 
                { 
                    error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr;
                    validation.Errors.Add(error); 
                    return null;
                }
            }
            finally 
            {
                validation.PopParentExpression(); 
            } 

            PropertyInfo pi = propExprInfo.PropertyInfo; 

            MethodInfo accessorMethod = isWritten ? pi.GetSetMethod(includeNonPublic) : pi.GetGetMethod(includeNonPublic);
            if (accessorMethod == null)
            { 
                string baseMessage = isWritten ? Messages.UnknownPropertySet : Messages.UnknownPropertyGet;
                message = string.Format(CultureInfo.CurrentCulture, baseMessage, pi.Name, RuleDecompiler.DecompileType(targetType)); 
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = indexerExpr;
                validation.Errors.Add(error); 
                return null;
            }

            if (!validation.ValidateMemberAccess(targetObject, targetType, accessorMethod, pi.Name, indexerExpr)) 
                return null;
 
            // Validate any RuleAttributes, if present. 
            object[] attrs = pi.GetCustomAttributes(typeof(RuleAttribute), true);
            if (attrs != null && attrs.Length > 0) 
            {
                Stack methodStack = new Stack();
                methodStack.Push(pi);
 
                bool allAttributesValid = true;
                foreach (RuleAttribute ruleAttr in attrs) 
                { 
                    if (!ruleAttr.Validate(validation, pi, targetType, pi.GetIndexParameters()))
                        allAttributesValid = false; 
                }

                methodStack.Pop();
 
                if (!allAttributesValid)
                    return null; 
            } 

            return propExprInfo; 
        }


        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            string message; 
 
            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression;
 
            // Evaluate the target object and get its type.
            CodeExpression targetObject = indexerExpr.TargetObject;
            RuleExpressionInfo targetExprInfo = analysis.Validation.ExpressionInfo(targetObject);
            if (targetExprInfo == null)  // Oops, someone forgot to validate. 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = targetObject;
                throw exception; 
            }

            // Get the property info from the validator so we can look for [RuleRead] and [RuleWrite] attributes.
            RulePropertyExpressionInfo propExprInfo = analysis.Validation.ExpressionInfo(indexerExpr) as RulePropertyExpressionInfo; 
            if (propExprInfo == null)  // Oops, someone forgot to validate.
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = indexerExpr; 
                throw exception;
            }

            PropertyInfo pi = propExprInfo.PropertyInfo; 

            // Look for RuleAttribute's on the invoked indexer property. 
            List attributedExprs = new List(); 
            analysis.AnalyzeRuleAttributes(pi, targetObject, qualifier, indexerExpr.Indices, pi.GetIndexParameters(), attributedExprs);
 
            // See if the target object needs default analysis.
            if (!attributedExprs.Contains(targetObject))
            {
                // The property had no [RuleRead] or [RuleWrite] attributes.  The target object is read or 
                // written (as the case may be).
 
                RuleExpressionWalker.AnalyzeUsage(analysis, targetObject, isRead, isWritten, qualifier); 
            }
 
            // See if any of the arguments need default analysis.
            for (int i = 0; i < indexerExpr.Indices.Count; ++i)
            {
                CodeExpression argExpr = indexerExpr.Indices[i]; 

                if (!attributedExprs.Contains(argExpr)) 
                { 
                    // Similar to the target object, we assume that this method can reads the value
                    // of the parameter, but none of its members. 
                    RuleExpressionWalker.AnalyzeUsage(analysis, argExpr, true, false, null);
                }
            }
        } 

        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution) 
        { 
            string message;
 
            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression;

            RulePropertyExpressionInfo propExprInfo = execution.Validation.ExpressionInfo(indexerExpr) as RulePropertyExpressionInfo;
            if (propExprInfo == null)  // Oops, someone forgot to validate. 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.ExpressionNotValidated); 
                InvalidOperationException exception = new InvalidOperationException(message); 
                exception.Data[RuleUserDataKeys.ErrorObject] = indexerExpr;
                throw exception; 
            }

            PropertyInfo pi = propExprInfo.PropertyInfo;
 
            // Evaluate the target...
            object target = RuleExpressionWalker.Evaluate(execution, indexerExpr.TargetObject).Value; 
 
            if (target == null)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.TargetEvaluatedNullIndexer);
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = indexerExpr;
                throw exception; 
            }
 
            // Evaluate the index arguments. 
            int actualArgCount = indexerExpr.Indices.Count;
            ParameterInfo[] parmInfos = pi.GetIndexParameters(); 
            object[] indexArgs = new object[parmInfos.Length];

            int numFixedParameters = parmInfos.Length;
            if (propExprInfo.NeedsParamsExpansion) 
                numFixedParameters -= 1;
 
            int i; 
            for (i = 0; i < numFixedParameters; ++i)
            { 
                Type argType = execution.Validation.ExpressionInfo(indexerExpr.Indices[i]).ExpressionType;
                RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, indexerExpr.Indices[i]);
                indexArgs[i] = Executor.AdjustType(argType, argResult.Value, parmInfos[i].ParameterType);
            } 

            if (numFixedParameters < actualArgCount) 
            { 
                // This target indexer had a params array, and we are calling it with an
                // expanded parameter list.  E.g., 
                //      int this[int x, params string[] y]
                // with the invocation:
                //      x.y[5, "crud", "kreeble", "glorp"]
                // We need to translate this to: 
                //      x.y[5, new string[] { "crud", "kreeble", "glorp" }]
 
                ParameterInfo lastParamInfo = parmInfos[numFixedParameters]; 

                Type arrayType = lastParamInfo.ParameterType; 
                System.Diagnostics.Debug.Assert(arrayType.IsArray);
                Type elementType = arrayType.GetElementType();

                Array paramsArray = (Array)arrayType.InvokeMember(arrayType.Name, BindingFlags.CreateInstance, null, null, new object[] { actualArgCount - i }, CultureInfo.CurrentCulture); 
                for (; i < actualArgCount; ++i)
                { 
                    Type argType = execution.Validation.ExpressionInfo(indexerExpr.Indices[i]).ExpressionType; 
                    RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, indexerExpr.Indices[i]);
                    paramsArray.SetValue(Executor.AdjustType(argType, argResult.Value, elementType), i - numFixedParameters); 
                }

                indexArgs[numFixedParameters] = paramsArray;
            } 

            RulePropertyResult result = new RulePropertyResult(pi, target, indexArgs); 
            return result; 
        }
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            string message;
 
            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression;
 
            CodeExpression targetObject = indexerExpr.TargetObject; 
            if (targetObject == null)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullIndexerTarget);
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = indexerExpr;
                throw exception; 
            }
 
            if (indexerExpr.Indices == null || indexerExpr.Indices.Count == 0) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.MissingIndexExpressions); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = indexerExpr;
                throw exception;
            } 

            RuleExpressionWalker.Decompile(stringBuilder, targetObject, indexerExpr); 
            stringBuilder.Append('['); 
            RuleExpressionWalker.Decompile(stringBuilder, indexerExpr.Indices[0], null);
            for (int i = 1; i < indexerExpr.Indices.Count; ++i) 
            {
                stringBuilder.Append(", ");
                RuleExpressionWalker.Decompile(stringBuilder, indexerExpr.Indices[i], null);
            } 
            stringBuilder.Append(']');
        } 
 
        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression;

            CodeExpression targetObject = RuleExpressionWalker.Clone(indexerExpr.TargetObject);
 
            CodeExpression[] indices = new CodeExpression[indexerExpr.Indices.Count];
            for (int i = 0; i < indices.Length; ++i) 
                indices[i] = RuleExpressionWalker.Clone(indexerExpr.Indices[i]); 

            CodeIndexerExpression newIndexer = new CodeIndexerExpression(targetObject, indices); 
            return newIndexer;
        }

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeIndexerExpression indexerExpr = (CodeIndexerExpression)expression; 
 
            CodeIndexerExpression indexerComperand = (CodeIndexerExpression)comperand;
            if (!RuleExpressionWalker.Match(indexerExpr.TargetObject, indexerComperand.TargetObject)) 
                return false;

            if (indexerExpr.Indices.Count != indexerComperand.Indices.Count)
                return false; 

            for (int i = 0; i < indexerExpr.Indices.Count; ++i) 
            { 
                if (!RuleExpressionWalker.Match(indexerExpr.Indices[i], indexerComperand.Indices[i]))
                    return false; 
            }

            return true;
        } 
    }
 
    #endregion 

    #region Array Indexer Expression (indexer properties) 

    // CodeArrayIndexerExpression
    internal class ArrayIndexerExpression : RuleExpressionInternal
    { 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            string message; 
            ValidationError error = null;
            Type targetType = null; 

            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression;

            CodeExpression targetObject = arrayIndexerExpr.TargetObject; 
            if (targetObject == null)
            { 
                error = new ValidationError(Messages.NullIndexerTarget, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr;
                validation.Errors.Add(error); 
                return null;
            }

            if (targetObject is CodeTypeReferenceExpression) 
            {
                error = new ValidationError(Messages.IndexersCannotBeStatic, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr; 
                validation.Errors.Add(error);
                return null; 
            }

            if (arrayIndexerExpr.Indices == null || arrayIndexerExpr.Indices.Count == 0)
            { 
                error = new ValidationError(Messages.MissingIndexExpressions, ErrorNumbers.Error_ParameterNotSet);
                error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr; 
                validation.Errors.Add(error); 
                return null;
            } 

            try
            {
                // Early exit from this if a cycle is detected. 
                if (!validation.PushParentExpression(arrayIndexerExpr))
                    return null; 
 
                RuleExpressionInfo targetExprInfo = RuleExpressionWalker.Validate(validation, arrayIndexerExpr.TargetObject, false);
                if (targetExprInfo == null)		// error occurred, so simply return 
                    return null;

                targetType = targetExprInfo.ExpressionType;
                if (targetType == null) 
                    return null;
 
                // if an error occurred (targetType == null), continue on to validate the arguments 
                if (targetType == typeof(NullLiteral))
                { 
                    error = new ValidationError(Messages.NullIndexerTarget, ErrorNumbers.Error_ParameterNotSet);
                    error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr;
                    validation.Errors.Add(error);
                    return null; 
                }
 
                // The target type better be an array. 
                if (!targetType.IsArray)
                { 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.CannotIndexType, RuleDecompiler.DecompileType(targetType));
                    error = new ValidationError(message, ErrorNumbers.Error_CannotIndexType);
                    error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr;
                    validation.Errors.Add(error); 
                    return null;
                } 
 
                int rank = targetType.GetArrayRank();
                if (arrayIndexerExpr.Indices.Count != rank) 
                {
                    message = string.Format(CultureInfo.CurrentCulture, Messages.ArrayIndexBadRank, rank);
                    error = new ValidationError(message, ErrorNumbers.Error_ArrayIndexBadRank);
                    error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr; 
                    validation.Errors.Add(error);
                    return null; 
                } 

                bool hasInvalidArgument = false; 
                for (int i = 0; i < arrayIndexerExpr.Indices.Count; ++i)
                {
                    CodeExpression argExpr = arrayIndexerExpr.Indices[i];
                    if (argExpr == null) 
                    {
                        error = new ValidationError(Messages.NullIndexExpression, ErrorNumbers.Error_ParameterNotSet); 
                        error.UserData[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr; 
                        validation.Errors.Add(error);
                        hasInvalidArgument = true; 
                    }
                    else
                    {
                        CodeDirectionExpression argDirection = argExpr as CodeDirectionExpression; 
                        if (argDirection != null)
                        { 
                            // No "ref" or "out" arguments are allowed on indexer arguments. 
                            error = new ValidationError(Messages.IndexerArgCannotBeRefOrOut, ErrorNumbers.Error_IndexerArgCannotBeRefOrOut);
                            error.UserData[RuleUserDataKeys.ErrorObject] = argExpr; 
                            validation.Errors.Add(error);
                            hasInvalidArgument = true;
                        }
 
                        if (argExpr is CodeTypeReferenceExpression)
                        { 
                            message = string.Format(CultureInfo.CurrentCulture, Messages.CodeExpressionNotHandled, argExpr.GetType().FullName); 
                            error = new ValidationError(message, ErrorNumbers.Error_CodeExpressionNotHandled);
                            error.UserData[RuleUserDataKeys.ErrorObject] = argExpr; 
                            validation.AddError(error);
                            hasInvalidArgument = true;
                        }
 
                        // Validate the argument.
                        RuleExpressionInfo argExprInfo = RuleExpressionWalker.Validate(validation, argExpr, false); 
                        if (argExprInfo != null) 
                        {
                            Type argType = argExprInfo.ExpressionType; 
                            TypeCode argTypeCode = Type.GetTypeCode(argType);

                            // Any type that is, or can be converted to: int or long.
                            switch (argTypeCode) 
                            {
                                case TypeCode.Byte: 
                                case TypeCode.Char: 
                                case TypeCode.Int16:
                                case TypeCode.Int32: 
                                case TypeCode.Int64:
                                case TypeCode.SByte:
                                case TypeCode.UInt16:
                                    break; 

                                default: 
                                    message = string.Format(CultureInfo.CurrentCulture, Messages.ArrayIndexBadType, RuleDecompiler.DecompileType(argType)); 
                                    error = new ValidationError(message, ErrorNumbers.Error_ArrayIndexBadType);
                                    error.UserData[RuleUserDataKeys.ErrorObject] = argExpr; 
                                    validation.Errors.Add(error);
                                    hasInvalidArgument = true;
                                    break;
                            } 
                        }
                        else 
                        { 
                            hasInvalidArgument = true;
                        } 
                    }
                }

                // Stop further validation if there was a problem with any of the arguments. 
                if (hasInvalidArgument)
                    return null; 
            } 
            finally
            { 
                validation.PopParentExpression();
            }

            // The result type is this array's element type. 
            return new RuleExpressionInfo(targetType.GetElementType());
        } 
 

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            // Analyze the target object, flowing down the qualifier from above.  An expression
            // like:
            //      this.a.b[2,3].c[4].d[5] = 99; 
            // should produce a path similar to:
            //      this/a/b/c/d 
 
            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression;
            RuleExpressionWalker.AnalyzeUsage(analysis, arrayIndexerExpr.TargetObject, isRead, isWritten, qualifier); 

            // Analyze the indexer arguments.  They are read.
            for (int i = 0; i < arrayIndexerExpr.Indices.Count; ++i)
                RuleExpressionWalker.AnalyzeUsage(analysis, arrayIndexerExpr.Indices[i], true, false, null); 
        }
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution) 
        {
            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression; 

            // Evaluate the target...
            object target = RuleExpressionWalker.Evaluate(execution, arrayIndexerExpr.TargetObject).Value;
 
            if (target == null)
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.TargetEvaluatedNullIndexer); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr; 
                throw exception;
            }

            // Evaluate the index arguments (converting them to "longs") 
            int actualArgCount = arrayIndexerExpr.Indices.Count;
            long[] indexArgs = new long[actualArgCount]; 
 
            for (int i = 0; i < actualArgCount; ++i)
            { 
                Type argType = execution.Validation.ExpressionInfo(arrayIndexerExpr.Indices[i]).ExpressionType;
                object argValue = RuleExpressionWalker.Evaluate(execution, arrayIndexerExpr.Indices[i]).Value;
                indexArgs[i] = (long)Executor.AdjustType(argType, argValue, typeof(long));
            } 

            RuleArrayElementResult result = new RuleArrayElementResult((Array)target, indexArgs); 
            return result; 
        }
 
        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            string message;
 
            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression;
 
            CodeExpression targetObject = arrayIndexerExpr.TargetObject; 
            if (targetObject == null)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.NullIndexerTarget);
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr;
                throw exception; 
            }
 
            if (arrayIndexerExpr.Indices == null || arrayIndexerExpr.Indices.Count == 0) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.MissingIndexExpressions); 
                RuleEvaluationException exception = new RuleEvaluationException(message);
                exception.Data[RuleUserDataKeys.ErrorObject] = arrayIndexerExpr;
                throw exception;
            } 

            RuleExpressionWalker.Decompile(stringBuilder, targetObject, arrayIndexerExpr); 
            stringBuilder.Append('['); 
            RuleExpressionWalker.Decompile(stringBuilder, arrayIndexerExpr.Indices[0], null);
            for (int i = 1; i < arrayIndexerExpr.Indices.Count; ++i) 
            {
                stringBuilder.Append(", ");
                RuleExpressionWalker.Decompile(stringBuilder, arrayIndexerExpr.Indices[i], null);
            } 
            stringBuilder.Append(']');
        } 
 
        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression;

            CodeExpression targetObject = RuleExpressionWalker.Clone(arrayIndexerExpr.TargetObject);
 
            CodeExpression[] indices = new CodeExpression[arrayIndexerExpr.Indices.Count];
            for (int i = 0; i < indices.Length; ++i) 
                indices[i] = RuleExpressionWalker.Clone(arrayIndexerExpr.Indices[i]); 

            CodeArrayIndexerExpression newIndexer = new CodeArrayIndexerExpression(targetObject, indices); 
            return newIndexer;
        }

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeArrayIndexerExpression arrayIndexerExpr = (CodeArrayIndexerExpression)expression; 
 
            CodeArrayIndexerExpression indexerComperand = (CodeArrayIndexerExpression)comperand;
            if (!RuleExpressionWalker.Match(arrayIndexerExpr.TargetObject, indexerComperand.TargetObject)) 
                return false;

            if (arrayIndexerExpr.Indices.Count != indexerComperand.Indices.Count)
                return false; 

            for (int i = 0; i < arrayIndexerExpr.Indices.Count; ++i) 
            { 
                if (!RuleExpressionWalker.Match(arrayIndexerExpr.Indices[i], indexerComperand.Indices[i]))
                    return false; 
            }

            return true;
        } 
    }
 
    #endregion 

    #region Object Create expression 
    internal class ObjectCreateExpression : RuleExpressionInternal
    {
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten)
        { 
            string message;
            ValidationError error; 
 
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression;
 
            if (isWritten)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeObjectCreateExpression).ToString());
                error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                validation.Errors.Add(error); 
                return null; 
            }
 
            if (createExpression.CreateType == null)
            {
                error = new ValidationError(Messages.NullTypeType, ErrorNumbers.Error_ParameterNotSet);
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                validation.Errors.Add(error);
                return null; 
            } 

            Type resultType = validation.ResolveType(createExpression.CreateType); 
            if (resultType == null)
                return null;

            // look up parameters 
            List parameters = new List();
            try 
            { 
                // Early exit from this if a cycle is detected.
                if (!validation.PushParentExpression(createExpression)) 
                    return null;

                bool hasInvalidArgument = false;
                for (int i = 0; i < createExpression.Parameters.Count; ++i) 
                {
                    CodeExpression parameter = createExpression.Parameters[i]; 
                    if (parameter == null) 
                    {
                        message = string.Format(CultureInfo.CurrentCulture, Messages.NullConstructorParameter, i.ToString(CultureInfo.CurrentCulture), RuleDecompiler.DecompileType(resultType)); 
                        error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                        error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                        validation.Errors.Add(error);
                        hasInvalidArgument = true; 
                    }
                    else 
                    { 
                        RuleExpressionInfo parameterInfo = RuleExpressionWalker.Validate(validation, parameter, false);
                        if (parameterInfo == null) 
                            hasInvalidArgument = true;
                        parameters.Add(parameter);
                    }
                } 
                // quit if parameters not valid
                if (hasInvalidArgument) 
                    return null; 
            }
            finally 
            {
                validation.PopParentExpression();
            }
 
            // see if we can find the matching constructor
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; 
            if (validation.AllowInternalMembers(resultType)) 
                bindingFlags |= BindingFlags.NonPublic;
 
            // creating a value-type object with no parameters can always be done
            if ((resultType.IsValueType) && (parameters.Count == 0))
                return new RuleExpressionInfo(resultType);
 
            // error if type is an abstract type
            if (resultType.IsAbstract) 
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(resultType));
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists); 
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                validation.Errors.Add(error);
                return null;
            } 

            RuleConstructorExpressionInfo constructorInvokeInfo = validation.ResolveConstructor(resultType, bindingFlags, parameters, out error); 
            if (constructorInvokeInfo == null) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(resultType)); 
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists);
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                validation.Errors.Add(error);
                return null; 
            }
 
            return constructorInvokeInfo; 
        }
 
        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier)
        {
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression;
 
            // check each parameter
            foreach (CodeExpression p in createExpression.Parameters) 
            { 
                RuleExpressionWalker.AnalyzeUsage(analysis, p, true, false, null);
            } 
        }

        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        { 
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression;
 
            if (createExpression.CreateType == null) 
            {
                RuleEvaluationException exception = new RuleEvaluationException(Messages.NullTypeType); 
                exception.Data[RuleUserDataKeys.ErrorObject] = createExpression;
                throw exception;
            }
 
            RuleExpressionInfo expressionInfo = execution.Validation.ExpressionInfo(createExpression);
            if (expressionInfo == null)  // Oops, someone forgot to validate. 
            { 
                InvalidOperationException exception = new InvalidOperationException(Messages.ExpressionNotValidated);
                exception.Data[RuleUserDataKeys.ErrorObject] = createExpression; 
                throw exception;
            }

            RuleConstructorExpressionInfo createExpressionInfo = expressionInfo as RuleConstructorExpressionInfo; 
            if (createExpressionInfo == null)
            { 
                // it's just a regular RuleExpressionInfo, which means this is a value-type with no parameters 
                return new RuleLiteralResult(Activator.CreateInstance(expressionInfo.ExpressionType));
            } 

            ConstructorInfo constructor = createExpressionInfo.ConstructorInfo;
            object[] arguments = null;
            RuleExpressionResult[] outArgumentResults = null; 

            if (createExpression.Parameters != null && createExpression.Parameters.Count > 0) 
            { 
                int actualArgCount = createExpression.Parameters.Count;
                ParameterInfo[] parmInfos = constructor.GetParameters(); 

                arguments = new object[parmInfos.Length];

                int numFixedParameters = parmInfos.Length; 
                if (createExpressionInfo.NeedsParamsExpansion)
                    numFixedParameters -= 1; 
 
                int i;
 
                // Evaluate the fixed portion of the parameter list.
                for (i = 0; i < numFixedParameters; ++i)
                {
                    Type argType = execution.Validation.ExpressionInfo(createExpression.Parameters[i]).ExpressionType; 
                    RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, createExpression.Parameters[i]);
 
                    // Special procesing of direction expressions to keep track of out arguments (& ref). 
                    CodeDirectionExpression direction = createExpression.Parameters[i] as CodeDirectionExpression;
                    if (direction != null && (direction.Direction == FieldDirection.Ref || direction.Direction == FieldDirection.Out)) 
                    {
                        // lazy creation of fieldsToSet
                        if (outArgumentResults == null)
                            outArgumentResults = new RuleExpressionResult[actualArgCount]; 
                        // keep track of this out expression so we can set it later
                        outArgumentResults[i] = argResult; 
                    } 

                    arguments[i] = Executor.AdjustType(argType, argResult.Value, parmInfos[i].ParameterType); 
                }

                if (numFixedParameters < actualArgCount)
                { 
                    // This target method had a params array, and we are calling it with an
                    // expanded parameter list.  E.g., 
                    //      void foo(int x, params string[] y) 
                    // with the invocation:
                    //      foo(5, "crud", "kreeble", "glorp") 
                    // We need to translate this to:
                    //      foo(5, new string[] { "crud", "kreeble", "glorp" })

                    ParameterInfo lastParamInfo = parmInfos[numFixedParameters]; 

                    Type arrayType = lastParamInfo.ParameterType; 
                    System.Diagnostics.Debug.Assert(arrayType.IsArray); 
                    Type elementType = arrayType.GetElementType();
 
                    Array paramsArray = Array.CreateInstance(elementType, actualArgCount - i);
                    for (; i < actualArgCount; ++i)
                    {
                        Type argType = execution.Validation.ExpressionInfo(createExpression.Parameters[i]).ExpressionType; 
                        RuleExpressionResult argResult = RuleExpressionWalker.Evaluate(execution, createExpression.Parameters[i]);
                        paramsArray.SetValue(Executor.AdjustType(argType, argResult.Value, elementType), i - numFixedParameters); 
                    } 

                    arguments[numFixedParameters] = paramsArray; 
                }
            }

            object result; 
            try
            { 
                result = constructor.Invoke(arguments); 
            }
            catch (TargetInvocationException e) 
            {
                // if there is no inner exception, leave it untouched
                if (e.InnerException == null)
                    throw; 
                string message = string.Format(CultureInfo.CurrentCulture,
                    Messages.Error_ConstructorInvoke, 
                    RuleDecompiler.DecompileType(createExpressionInfo.ExpressionType), 
                    e.InnerException.Message);
                throw new TargetInvocationException(message, e.InnerException); 
            }

            // any out/ref parameters that need to be assigned?
            if (outArgumentResults != null) 
            {
                for (int i = 0; i < createExpression.Parameters.Count; ++i) 
                { 
                    if (outArgumentResults[i] != null)
                        outArgumentResults[i].Value = arguments[i]; 
                }
            }
            return new RuleLiteralResult(result);		
        } 

        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression) 
        { 
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression;
 
            bool mustParenthesize = RuleDecompiler.MustParenthesize(createExpression, parentExpression);
            if (mustParenthesize)
                stringBuilder.Append("(");
 
            stringBuilder.Append("new ");
            RuleDecompiler.DecompileType(stringBuilder, createExpression.CreateType); 
 
            // Decompile the arguments
            stringBuilder.Append('('); 
            for (int i = 0; i < createExpression.Parameters.Count; ++i)
            {
                CodeExpression paramExpr = createExpression.Parameters[i];
                if (paramExpr == null) 
                {
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.NullConstructorTypeParameter, i.ToString(CultureInfo.CurrentCulture), createExpression.CreateType); 
                    RuleEvaluationException exception = new RuleEvaluationException(message); 
                    exception.Data[RuleUserDataKeys.ErrorObject] = createExpression;
                    throw exception; 
                }

                if (i > 0)
                    stringBuilder.Append(", "); 

                RuleExpressionWalker.Decompile(stringBuilder, paramExpr, null); 
            } 
            stringBuilder.Append(')');
 
            if (mustParenthesize)
                stringBuilder.Append(")");
        }
 
        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression; 

            CodeObjectCreateExpression newCreate = new CodeObjectCreateExpression(); 
            newCreate.CreateType = TypeReferenceExpression.CloneType(createExpression.CreateType);
            foreach (CodeExpression p in createExpression.Parameters)
            {
                newCreate.Parameters.Add(RuleExpressionWalker.Clone(p)); 
            }
            return newCreate; 
        } 

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeObjectCreateExpression createExpression = (CodeObjectCreateExpression)expression;

            CodeObjectCreateExpression createComperand = comperand as CodeObjectCreateExpression; 
            if (createComperand == null)
                return false; 
            // check types 
            if (!TypeReferenceExpression.MatchType(createExpression.CreateType, createComperand.CreateType))
                return false; 
            // check parameters
            if (createExpression.Parameters.Count != createComperand.Parameters.Count)
                return false;
            for (int i = 0; i < createExpression.Parameters.Count; ++i) 
                if (!RuleExpressionWalker.Match(createExpression.Parameters[i], createComperand.Parameters[i]))
                    return false; 
            return true; 
        }
    } 
    #endregion

    #region Array Create expression
    internal class ArrayCreateExpression : RuleExpressionInternal 
    {
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        internal override RuleExpressionInfo Validate(CodeExpression expression, RuleValidation validation, bool isWritten) 
        {
            string message; 

            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression;

            if (isWritten) 
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotWriteToExpression, typeof(CodeObjectCreateExpression).ToString()); 
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_InvalidAssignTarget); 
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                validation.Errors.Add(error); 
                return null;
            }

            if (createExpression.CreateType == null) 
            {
                ValidationError error = new ValidationError(Messages.NullTypeType, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                validation.Errors.Add(error);
                return null; 
            }

            Type resultType = validation.ResolveType(createExpression.CreateType);
            if (resultType == null) 
                return null;
 
            // size CodeDom has limited support for arrays (only 1 dimensional, not more) 
            // we limit CodeArrayCreateExpression to a single dimension
            // (i.e. CodeArrayCreateExpression cannot define int[5,3] or int[5][3], 
            // but it is possible to define int[][3] and then use initializers to
            // fill it in. But we only support int[] or int[3].)
            if (resultType.IsArray)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.ArrayTypeInvalid, resultType.Name);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet); 
                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                validation.Errors.Add(error);
                return null; 
            }

            try
            { 
                // Early exit from this if a cycle is detected.
                if (!validation.PushParentExpression(createExpression)) 
                    return null; 

                if (createExpression.Size < 0) 
                {
                    ValidationError error = new ValidationError(Messages.ArraySizeInvalid, ErrorNumbers.Error_ParameterNotSet);
                    error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                    validation.Errors.Add(error); 
                    return null;
                } 
 
                // look up size (if specified)
                if (createExpression.SizeExpression != null) 
                {
                    RuleExpressionInfo sizeInfo = RuleExpressionWalker.Validate(validation, createExpression.SizeExpression, false);
                    if (sizeInfo == null)
                        return null; 
                    if ((sizeInfo.ExpressionType != typeof(int))
                        && (sizeInfo.ExpressionType != typeof(uint)) 
                        && (sizeInfo.ExpressionType != typeof(long)) 
                        && (sizeInfo.ExpressionType != typeof(ulong)))
                    { 
                        message = string.Format(CultureInfo.CurrentCulture, Messages.ArraySizeTypeInvalid, sizeInfo.ExpressionType.Name);
                        ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet);
                        error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                        validation.Errors.Add(error); 
                        return null;
                    } 
                } 
                bool parameterInvalid = false;
                for (int i = 0; i < createExpression.Initializers.Count; ++i) 
                {
                    CodeExpression init = createExpression.Initializers[i];
                    if (init == null)
                    { 
                        message = string.Format(CultureInfo.CurrentCulture, Messages.MissingInitializer, resultType.Name);
                        ValidationError error = new ValidationError(message, ErrorNumbers.Error_ParameterNotSet); 
                        error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                        validation.Errors.Add(error);
                        return null; 
                    }
                    RuleExpressionInfo parameterInfo = RuleExpressionWalker.Validate(validation, init, false);
                    if (parameterInfo == null)
                    { 
                        parameterInvalid = true;
                    } 
                    else 
                    {
                        // can we convert the result type to the array type? 
                        ValidationError error;
                        if (!RuleValidation.StandardImplicitConversion(parameterInfo.ExpressionType, resultType, init, out error))
                        {
                            // types must match 
                            if (error != null)
                            { 
                                // we got an error from the conversion, so give it back as well as a new error 
                                error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                                validation.Errors.Add(error); 
                            }
                            message = string.Format(CultureInfo.CurrentCulture, Messages.InitializerMismatch, i, resultType.Name);
                            error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                            error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                            validation.Errors.Add(error);
                            return null; 
                        } 
                    }
                } 
                // if any errors get out
                if (parameterInvalid)
                    return null;
 
                // now it gets tricky. CodeArrayCreateExpression constructors allow:
                //     1) size as int 
                //     2) size as CodeExpression 
                //     3) initializers as params array
                // However, we allow a size and initializers, so try to verify size >= #initializers 
                // size can be an int, uint, long, or ulong
                double size = -1;
                if (createExpression.SizeExpression != null)
                { 
                    CodePrimitiveExpression prim = createExpression.SizeExpression as CodePrimitiveExpression;
                    if ((prim != null) && (prim.Value != null)) 
                        size = (double)Executor.AdjustType(prim.Value.GetType(), prim.Value, typeof(double)); 
                    if (createExpression.Size > 0)
                    { 
                        // both size and SizeExpression specified, complain
                        ValidationError error = new ValidationError(Messages.ArraySizeBoth, ErrorNumbers.Error_ParameterNotSet);
                        error.UserData[RuleUserDataKeys.ErrorObject] = createExpression;
                        validation.Errors.Add(error); 
                        return null;
                    } 
                } 
                else if (createExpression.Size > 0)
                    size = createExpression.Size; 

                if ((size >= 0) && (createExpression.Initializers.Count > size))
                {
                    message = string.Format(CultureInfo.CurrentCulture, Messages.InitializerCountMismatch, createExpression.Initializers.Count, size); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                    error.UserData[RuleUserDataKeys.ErrorObject] = createExpression; 
                    validation.Errors.Add(error); 
                    return null;
                } 
            }
            finally
            {
                validation.PopParentExpression(); 
            }
            return new RuleExpressionInfo(resultType.MakeArrayType()); 
        } 

        internal override void AnalyzeUsage(CodeExpression expression, RuleAnalysis analysis, bool isRead, bool isWritten, RulePathQualifier qualifier) 
        {
            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression;

            if (createExpression.SizeExpression != null) 
                RuleExpressionWalker.AnalyzeUsage(analysis, createExpression.SizeExpression, true, false, null);
            foreach (CodeExpression p in createExpression.Initializers) 
                RuleExpressionWalker.AnalyzeUsage(analysis, p, true, false, null); 
        }
 
        internal override RuleExpressionResult Evaluate(CodeExpression expression, RuleExecution execution)
        {
            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression;
 
            if (createExpression.CreateType == null)
            { 
                RuleEvaluationException exception = new RuleEvaluationException(Messages.NullTypeType); 
                exception.Data[RuleUserDataKeys.ErrorObject] = createExpression;
                throw exception; 
            }

            RuleExpressionInfo createExpressionInfo = execution.Validation.ExpressionInfo(createExpression);
            if (createExpression == null)  // Oops, someone forgot to validate. 
            {
                InvalidOperationException exception = new InvalidOperationException(Messages.ExpressionNotValidated); 
                exception.Data[RuleUserDataKeys.ErrorObject] = createExpression; 
                throw exception;
            } 

            // type should be an array type already
            Type type = createExpressionInfo.ExpressionType;
            Type elementType = type.GetElementType(); 

            // assume this has been validated, so only 1 size specified 
            int size = 0; 
            if (createExpression.SizeExpression != null)
            { 
                Type sizeType = execution.Validation.ExpressionInfo(createExpression.SizeExpression).ExpressionType;
                RuleExpressionResult sizeResult = RuleExpressionWalker.Evaluate(execution, createExpression.SizeExpression);
                if (sizeType == typeof(int))
                    size = (int)sizeResult.Value; 
                else if (sizeType == typeof(long))
                    size = (int)((long)sizeResult.Value); 
                else if (sizeType == typeof(uint)) 
                    size = (int)((uint)sizeResult.Value);
                else if (sizeType == typeof(ulong)) 
                    size = (int)((ulong)sizeResult.Value);
            }
            else if (createExpression.Size != 0)
                size = createExpression.Size; 
            else
                size = createExpression.Initializers.Count; 
 
            Array result = Array.CreateInstance(elementType, size);
            if (createExpression.Initializers != null) 
                for (int i = 0; i < createExpression.Initializers.Count; ++i)
                {
                    CodeExpression initializer = createExpression.Initializers[i];
                    Type initializerType = execution.Validation.ExpressionInfo(initializer).ExpressionType; 
                    RuleExpressionResult initializerResult = RuleExpressionWalker.Evaluate(execution, initializer);
                    result.SetValue(Executor.AdjustType(initializerType, initializerResult.Value, elementType), i); 
                } 
            return new RuleLiteralResult(result);
        } 

        internal override void Decompile(CodeExpression expression, StringBuilder stringBuilder, CodeExpression parentExpression)
        {
            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression; 

            bool mustParenthesize = RuleDecompiler.MustParenthesize(createExpression, parentExpression); 
            if (mustParenthesize) 
                stringBuilder.Append("(");
 
            stringBuilder.Append("new ");
            RuleDecompiler.DecompileType(stringBuilder, createExpression.CreateType);
            stringBuilder.Append('[');
            if (createExpression.SizeExpression != null) 
                RuleExpressionWalker.Decompile(stringBuilder, createExpression.SizeExpression, null);
            else if ((createExpression.Size != 0) || (createExpression.Initializers.Count == 0)) 
                stringBuilder.Append(createExpression.Size); 
            stringBuilder.Append(']');
            if (createExpression.Initializers.Count > 0) 
            {
                stringBuilder.Append(" { ");
                for (int i = 0; i < createExpression.Initializers.Count; ++i)
                { 
                    CodeExpression paramExpr = createExpression.Initializers[i];
                    if (paramExpr == null) 
                    { 
                        string message = string.Format(CultureInfo.CurrentCulture, Messages.NullConstructorTypeParameter, i.ToString(CultureInfo.CurrentCulture), createExpression.CreateType);
                        RuleEvaluationException exception = new RuleEvaluationException(message); 
                        exception.Data[RuleUserDataKeys.ErrorObject] = createExpression;
                        throw exception;
                    }
 
                    if (i > 0)
                        stringBuilder.Append(", "); 
 
                    RuleExpressionWalker.Decompile(stringBuilder, paramExpr, null);
                } 
                stringBuilder.Append('}');
            }

            if (mustParenthesize) 
                stringBuilder.Append(")");
        } 
 
        internal override CodeExpression Clone(CodeExpression expression)
        { 
            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression;

            CodeArrayCreateExpression newCreate = new CodeArrayCreateExpression();
            newCreate.CreateType = TypeReferenceExpression.CloneType(createExpression.CreateType); 
            newCreate.Size = createExpression.Size;
            if (createExpression.SizeExpression != null) 
                newCreate.SizeExpression = RuleExpressionWalker.Clone(createExpression.SizeExpression); 
            foreach (CodeExpression p in createExpression.Initializers)
                newCreate.Initializers.Add(RuleExpressionWalker.Clone(p)); 
            return newCreate;
        }

        internal override bool Match(CodeExpression expression, CodeExpression comperand) 
        {
            CodeArrayCreateExpression createExpression = (CodeArrayCreateExpression)expression; 
 
            CodeArrayCreateExpression createComperand = comperand as CodeArrayCreateExpression;
            if ((createComperand == null) 
                || (createExpression.Size != createComperand.Size)
                || (!TypeReferenceExpression.MatchType(createExpression.CreateType, createComperand.CreateType)))
                return false;
            // check SizeExpression, if it exists 
            if (createExpression.SizeExpression != null)
            { 
                if (createComperand.SizeExpression == null) 
                    return false;
                if (!RuleExpressionWalker.Match(createExpression.SizeExpression, createComperand.SizeExpression)) 
                    return false;
            }
            else
            { 
                if (createComperand.SizeExpression != null)
                    return false; 
            } 
            // check initializers
            if (createExpression.Initializers.Count != createComperand.Initializers.Count) 
                return false;
            for (int i = 0; i < createExpression.Initializers.Count; ++i)
                if (!RuleExpressionWalker.Match(createExpression.Initializers[i], createComperand.Initializers[i]))
                    return false; 
            return true;
        } 
    } 
    #endregion
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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