XPathCompiler.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Dispatcher / XPathCompiler.cs / 1 / XPathCompiler.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{ 
    using System.Diagnostics;
    using System.Xml; 
    using System.Xml.XPath; 

    // The compiler RECURSIVELY consumes xpath expression trees. 
    internal class XPathCompiler
    {
        QueryCompilerFlags flags;
        int nestingLevel; 
        bool pushInitialContext;
 
#if FILTEROPTIMIZER 
        FilterOptimizer optimizer;
 
        internal XPathCompiler(FilterOptimizer optimizer, QueryCompilerFlags flags)
        {
            this.optimizer = optimizer;
            this.flags = flags; 
            this.pushInitialContext = false;
        } 
 
        internal XPathCompiler(QueryCompilerFlags flags)
            : this(new FilterOptimizer(SelectFunctionTree.standard), flags) 
        {
        }
#else
        internal XPathCompiler(QueryCompilerFlags flags) 
        {
            this.flags = flags; 
            this.pushInitialContext = false; 
        }
#endif 

        void SetPushInitialContext(bool pushInitial)
        {
            if (pushInitial) 
            {
                this.pushInitialContext = pushInitial; 
            } 
        }
 
        // Compiles top level expressions
        internal virtual OpcodeBlock Compile(XPathExpr expr)
        {
            DiagnosticUtility.DebugAssert(null != expr, ""); 

            this.nestingLevel = 1; 
            this.pushInitialContext = false; 

            XPathExprCompiler exprCompiler = new XPathExprCompiler(this); 
            OpcodeBlock mainBlock = exprCompiler.Compile(expr);
            if (this.pushInitialContext)
            {
                OpcodeBlock expandedBlock = new OpcodeBlock(); 
                expandedBlock.Append(new PushContextNodeOpcode());
                expandedBlock.Append(mainBlock); 
                expandedBlock.Append(new PopContextNodes()); 
                return expandedBlock;
            } 
            return mainBlock;
        }

        // Implemented as a struct because it is cheap to allocate and the Expression compiler is 
        // allocated a lot!
        internal struct XPathExprCompiler 
        { 
            OpcodeBlock codeBlock;
            XPathCompiler compiler; 

            internal XPathExprCompiler(XPathCompiler compiler)
            {
                DiagnosticUtility.DebugAssert(null != compiler, ""); 
                this.compiler = compiler;
                this.codeBlock = new OpcodeBlock(); 
            } 

            XPathExprCompiler(XPathExprCompiler xpathCompiler) 
            {
                this.compiler = xpathCompiler.compiler;
                this.codeBlock = new OpcodeBlock();
            } 

            internal OpcodeBlock Compile(XPathExpr expr) 
            { 
                this.codeBlock = new OpcodeBlock(); // struct
                this.CompileExpression(expr); 
                return this.codeBlock;
            }

            OpcodeBlock CompileBlock(XPathExpr expr) 
            {
                XPathExprCompiler compiler = new XPathExprCompiler(this); 
                return compiler.Compile(expr); 
            }
 
            void CompileBoolean(XPathExpr expr, bool testValue)
            {
                // Boolean expressions must always have at least 2 sub expressions
                DiagnosticUtility.DebugAssert(expr.SubExprCount > 1, ""); 

                if (this.compiler.nestingLevel == 1) 
                { 
                    this.CompileBasicBoolean(expr, testValue);
                    return; 
                }

                OpcodeBlock boolBlock = new OpcodeBlock(); // struct
                Opcode blockEnd = new BlockEndOpcode(); 
                // Set up the result mask
                boolBlock.Append(new PushBooleanOpcode(testValue)); 
                XPathExprList subExprList = expr.SubExpr; 
                XPathExpr subExpr;
 
                // the first expression needs the least work..
                subExpr = subExprList[0];
                boolBlock.Append(this.CompileBlock(subExpr));
                if (subExpr.ReturnType != ValueDataType.Boolean) 
                {
                    boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean)); 
                } 
                boolBlock.Append(new ApplyBooleanOpcode(blockEnd, testValue));
 
                // Compile remaining sub-expressions
                for (int i = 1; i < subExprList.Count; ++i)
                {
                    subExpr = subExprList[i]; 
                    boolBlock.Append(new StartBooleanOpcode(testValue));
                    boolBlock.Append(this.CompileBlock(subExpr)); 
                    // Make sure each sub-expression can produce a boolean result 
                    if (subExpr.ReturnType != ValueDataType.Boolean)
                    { 
                        boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean));
                    }
                    boolBlock.Append(new EndBooleanOpcode(blockEnd, testValue));
                } 
                boolBlock.Append(blockEnd);
                this.codeBlock.Append(boolBlock); 
            } 

            // Compiles expressions at nesting level == 1 -> boolean expressions that can be processed 
            // with less complex opcodes because they will never track multiple sequences simultaneously
            void CompileBasicBoolean(XPathExpr expr, bool testValue)
            {
                // Boolean expressions must always have at least 2 sub expressions 
                DiagnosticUtility.DebugAssert(expr.SubExprCount > 1, "");
                DiagnosticUtility.DebugAssert(this.compiler.nestingLevel == 1, ""); 
 
                OpcodeBlock boolBlock = new OpcodeBlock(); // struct
                Opcode blockEnd = new BlockEndOpcode(); 
                XPathExprList subExprList = expr.SubExpr;

                // Compile sub-expressions
                for (int i = 0; i < subExprList.Count; ++i) 
                {
                    XPathExpr subExpr = subExprList[i]; 
                    boolBlock.Append(this.CompileBlock(subExpr)); 
                    // Make sure each sub-expression can produce a boolean result
                    if (subExpr.ReturnType != ValueDataType.Boolean) 
                    {
                        boolBlock.Append(new TypecastOpcode(ValueDataType.Boolean));
                    }
                    if (i < (subExprList.Count - 1)) 
                    {
                        // No point jumping if this is the last expression 
                        boolBlock.Append(new JumpIfOpcode(blockEnd, testValue)); 
                    }
                } 
                boolBlock.Append(blockEnd);
                this.codeBlock.Append(boolBlock);
            }
 
            void CompileExpression(XPathExpr expr)
            { 
                DiagnosticUtility.DebugAssert(null != expr, ""); 

                switch (expr.Type) 
                {
                    default:
                        this.ThrowError(QueryCompileError.UnsupportedExpression);
                        break; 

                    case XPathExprType.And: 
                        this.CompileBoolean(expr, true); 
                        break;
 
                    case XPathExprType.Or:
                        this.CompileBoolean(expr, false);
                        break;
 
                    case XPathExprType.Relational:
                        this.CompileRelational((XPathRelationExpr) expr); 
                        break; 

                    case XPathExprType.Function: 
                        this.CompileFunction((XPathFunctionExpr)expr);
                        break;

                    case XPathExprType.Union: 
                        {
                        XPathConjunctExpr unionExpr = (XPathConjunctExpr) expr; 
                        this.CompileExpression(unionExpr.Left); 
                        this.CompileExpression(unionExpr.Right);
                        this.codeBlock.Append(new UnionOpcode()); 
                        }
                        break;

                    case XPathExprType.RelativePath: 
                        this.CompileRelativePath(expr, true);
                        break; 
 
                    case XPathExprType.LocationPath:
                        if (expr.SubExprCount > 0) 
                        {
                            this.CompileLocationPath(expr);
                            // Step complete. Transfer results onto the value stack
                            this.codeBlock.Append(new PopSequenceToValueStackOpcode()); 
                        }
                        break; 
 
                    case XPathExprType.Math:
                        this.CompileMath((XPathMathExpr) expr); 
                        break;

                    case XPathExprType.Number:
                        XPathNumberExpr number = (XPathNumberExpr) expr; 
                        double literal = number.Number;
                        if (number.Negate) 
                        { 
                            number.Negate = false;
                            literal = -literal; 
                        }
                        this.codeBlock.Append(new PushNumberOpcode(literal));
                        break;
 
                    case XPathExprType.String:
                        this.codeBlock.Append(new PushStringOpcode(((XPathStringExpr) expr).String)); 
                        break; 

                    case XPathExprType.Filter: 
                        this.CompileFilter(expr);
                        if(expr.ReturnType == ValueDataType.Sequence)
                        {
                            this.codeBlock.Append(new PopSequenceToValueStackOpcode()); 
                        }
                        break; 
 
                    case XPathExprType.Path:
                        this.CompilePath(expr); 
                        if(expr.SubExprCount == 0 && expr.ReturnType == ValueDataType.Sequence)
                        {
                            this.codeBlock.Append(new PopSequenceToValueStackOpcode());
                        } 
                        break;
 
                    case XPathExprType.XsltFunction: 
                        this.CompileXsltFunction((XPathXsltFunctionExpr)expr);
                        break; 

                    case XPathExprType.XsltVariable:
                        this.CompileXsltVariable((XPathXsltVariableExpr)expr);
                        break; 
                }
 
                NegateIfRequired(expr); 
            }
 
            void CompileFilter(XPathExpr expr)
            {
                DiagnosticUtility.DebugAssert(XPathExprType.Filter == expr.Type, "");
                // The filter expression has two components - the expression and its predicate 
                // It may have an optional relative path following it
                //Debug.Assert(expr.SubExprCount <= 3); 
                XPathExprList subExpr = expr.SubExpr; 

                XPathExpr filterExpr = subExpr[0]; 
                if (subExpr.Count > 1 && ValueDataType.Sequence != filterExpr.ReturnType)
                {
                    this.ThrowError(QueryCompileError.InvalidExpression);
                } 
                // The filter expression will return a sequence and push it onto the value stack
                // Transfer it back to the sequence stack, so we can keep working on it 
                this.CompileExpression(filterExpr); 
                if(filterExpr.ReturnType == ValueDataType.Sequence)
                { 
                    if(!IsSpecialInternalFunction(filterExpr) && expr.SubExprCount > 1)
                    {
                        // Flatten the sequence and move it to the sequence stack
                        this.codeBlock.Append(new MergeOpcode()); 
                        this.codeBlock.Append(new PopSequenceToSequenceStackOpcode());
                    } 
                    else if(IsSpecialInternalFunction(filterExpr) && expr.SubExprCount > 1) 
                    {
                        this.codeBlock.DetachLast(); 
                    }

                    // Now, apply the predicates
                    this.compiler.nestingLevel++; 
                    if(this.compiler.nestingLevel > 3) // throw if we find something deepter than [ [ ] ]
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); 
                    }
                    for(int i = 1; i < expr.SubExprCount; ++i) 
                    {
                        this.CompilePredicate(subExpr[i]);
                    }
                    this.compiler.nestingLevel--; 
                }
            } 
 
            bool IsSpecialInternalFunction(XPathExpr expr)
            { 
                if(expr.Type != XPathExprType.XsltFunction)
                {
                    return false;
                } 

                XPathMessageFunction func = ((XPathXsltFunctionExpr)expr).Function as XPathMessageFunction; 
                if(func != null) 
                {
                    return func.ReturnType == XPathResultType.NodeSet && func.Maxargs == 0; 
                }

                return false;
            } 

            void CompileFunction(XPathFunctionExpr expr) 
            { 
                // In some scenarios, some functions are handled in a special way
                if (this.CompileFunctionSpecial(expr)) 
                {
                    return;
                }
 
                // Generic function compilation
                QueryFunction function = expr.Function; 
                // Compile each argument expression first, introducing a typecast where appropriate 
                // Arguments are pushed C style - right to left
                if (expr.SubExprCount > 0) 
                {
                    XPathExprList paramList = expr.SubExpr;
                    for (int i = paramList.Count - 1; i >= 0; --i)
                    { 
                        this.CompileFunctionParam(function, expr.SubExpr, i);
                    } 
                } 
                this.codeBlock.Append(new FunctionCallOpcode(function));
                if (1 == this.compiler.nestingLevel && function.TestFlag(QueryFunctionFlag.UsesContextNode)) 
                {
                    this.compiler.SetPushInitialContext(true);
                }
            } 

            void CompileFunctionParam(QueryFunction function, XPathExprList paramList, int index) 
            { 
                XPathExpr param = paramList[index];
                this.CompileExpression(param); 
                if (ValueDataType.None != function.ParamTypes[index])
                {
                    if (param.ReturnType != function.ParamTypes[index])
                    { 
                        if(function.ParamTypes[index] == ValueDataType.Sequence)
                        { 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.InvalidTypeConversion)); 
                        }
 
                        this.CompileTypecast(function.ParamTypes[index]);
                    }
                }
            } 

            // Some functions are compiled with special opcodes to optimize perf in special situations 
            // 1. starts-with(string, literal) 
            bool CompileFunctionSpecial(XPathFunctionExpr expr)
            { 
                XPathFunction function = expr.Function as XPathFunction;
                if (null != function)
                {
                    if (XPathFunctionID.StartsWith == function.ID) 
                    {
                        // Does the 2nd parameter start with a string literal? Use a special opcode to handle those.. 
                        DiagnosticUtility.DebugAssert(expr.SubExprCount == 2, ""); 
                        if (XPathExprType.String == expr.SubExpr[1].Type)
                        { 
                            this.CompileFunctionParam(function, expr.SubExpr, 0);
                            this.codeBlock.Append(new StringPrefixOpcode(((XPathStringExpr)expr.SubExpr[1]).String));
                            return true;
                        } 
                    }
                } 
 
                return false;
            } 

            void CompileLiteralRelation(XPathRelationExpr expr)
            {
                XPathLiteralExpr left = (XPathLiteralExpr) expr.Left; 
                XPathLiteralExpr right = (XPathLiteralExpr) expr.Right;
 
                bool result = QueryValueModel.CompileTimeCompare(left.Literal, right.Literal, expr.Op); 
                this.codeBlock.Append(new PushBooleanOpcode(result));
            } 

            void CompileLiteralOrdinal(XPathExpr expr)
            {
                int ordinal = 0; 
                try
                { 
                    XPathNumberExpr numExpr = (XPathNumberExpr) expr; 
                    ordinal = Convert.ToInt32(numExpr.Number);
                    if(numExpr.Negate) 
                    {
                        ordinal = -ordinal;
                        numExpr.Negate = false;
                    } 
                    if (ordinal < 1)
                    { 
                        this.ThrowError(QueryCompileError.InvalidOrdinal); 
                    }
                } 
                catch (OverflowException)
                {
                    this.ThrowError(QueryCompileError.InvalidOrdinal);
                } 

                if (0 != (this.compiler.flags & QueryCompilerFlags.InverseQuery)) 
                { 
                    this.codeBlock.Append(new PushContextPositionOpcode());
                    this.codeBlock.Append(new NumberEqualsOpcode(ordinal)); 
                }
                else
                {
                    this.codeBlock.Append(new LiteralOrdinalOpcode(ordinal)); 
                }
            } 
 
            void CompileLocationPath(XPathExpr expr)
            { 
                DiagnosticUtility.DebugAssert(expr.SubExprCount > 0, "");

                XPathStepExpr firstStep = (XPathStepExpr) expr.SubExpr[0];
 
                this.CompileSteps(expr.SubExpr);
 
                if (1 == this.compiler.nestingLevel) 
                {
                    this.compiler.SetPushInitialContext(firstStep.SelectDesc.Type != QueryNodeType.Root); 
                }
            }

            void CompileMath(XPathMathExpr mathExpr) 
            {
                // are we doing math on two literal numbers? If so, do it at compile time 
                if (XPathExprType.Number == mathExpr.Right.Type && XPathExprType.Number == mathExpr.Left.Type) 
                {
                    double left = ((XPathNumberExpr) mathExpr.Left).Number; 
                    if(((XPathNumberExpr) mathExpr.Left).Negate)
                    {
                        ((XPathNumberExpr) mathExpr.Left).Negate = false;
                        left = -left; 
                    }
                    double right = ((XPathNumberExpr) mathExpr.Right).Number; 
                    if(((XPathNumberExpr) mathExpr.Right).Negate) 
                    {
                        ((XPathNumberExpr) mathExpr.Right).Negate = false; 
                        right = -right;
                    }
                    switch (mathExpr.Op)
                    { 
                        case MathOperator.Div:
                            left /= right; 
                            break; 
                        case MathOperator.Minus:
                            left -= right; 
                            break;
                        case MathOperator.Mod:
                            left %= right;
                            break; 
                        case MathOperator.Multiply:
                            left *= right; 
                            break; 
                        case MathOperator.Plus:
                            left += right; 
                            break;
                    }
                    this.codeBlock.Append(new PushNumberOpcode(left));
                    return; 
                }
 
                // Arguments are pushed C style - right to left 
                this.CompileExpression(mathExpr.Right);
                if (ValueDataType.Double != mathExpr.Right.ReturnType) 
                {
                    this.CompileTypecast(ValueDataType.Double);
                }
                this.CompileExpression(mathExpr.Left); 
                if (ValueDataType.Double != mathExpr.Left.ReturnType)
                { 
                    this.CompileTypecast(ValueDataType.Double); 
                }
                this.codeBlock.Append(this.CreateMathOpcode(mathExpr.Op)); 
            }

            void CompileNumberLiteralEquality(XPathRelationExpr expr)
            { 
                DiagnosticUtility.DebugAssert(expr.Op == RelationOperator.Eq, "");
 
                bool leftNumber = (XPathExprType.Number == expr.Left.Type); 
                bool rightNumber = (XPathExprType.Number == expr.Right.Type);
 
                DiagnosticUtility.DebugAssert(leftNumber || rightNumber, "");
                DiagnosticUtility.DebugAssert(!(leftNumber && rightNumber), "");

                this.CompileExpression(leftNumber ? expr.Right : expr.Left); 
                XPathNumberExpr litExpr = leftNumber ? (XPathNumberExpr) expr.Left : (XPathNumberExpr) expr.Right;
                double literal = litExpr.Number; 
                if(litExpr.Negate) 
                {
                    litExpr.Negate = false; 
                    literal = -literal;
                }
                this.codeBlock.Append(new NumberEqualsOpcode(literal));
            } 

            void CompileNumberRelation(XPathRelationExpr expr) 
            { 
                if (expr.Op == RelationOperator.Eq)
                { 
                    this.CompileNumberLiteralEquality(expr);
                    return;
                }
 
                bool leftNumber = (XPathExprType.Number == expr.Left.Type);
                bool rightNumber = (XPathExprType.Number == expr.Right.Type); 
                DiagnosticUtility.DebugAssert(leftNumber || rightNumber, ""); 
                DiagnosticUtility.DebugAssert(!(leftNumber && rightNumber), "");
 
                this.CompileExpression(leftNumber ? expr.Right : expr.Left);
                XPathNumberExpr litExpr = leftNumber ? (XPathNumberExpr) expr.Left : (XPathNumberExpr) expr.Right;
                double literal = litExpr.Number;
                if(litExpr.Negate) 
                {
                    litExpr.Negate = false; 
                    literal = -literal; 
                }
 
                // To maximize code branch commonality, we canonacalize the relation expressions so that the non-literal
                // is always to the left and the literal to the right. If this makes us swap expressions, we must also flip
                // relation operators appropriately.
                if (leftNumber) 
                {
                    // Flip operators 
                    switch (expr.Op) 
                    {
                        case RelationOperator.Gt: 
                            expr.Op = RelationOperator.Lt;
                            break;
                        case RelationOperator.Ge:
                            expr.Op = RelationOperator.Le; 
                            break;
                        case RelationOperator.Lt: 
                            expr.Op = RelationOperator.Gt; 
                            break;
                        case RelationOperator.Le: 
                            expr.Op = RelationOperator.Ge;
                            break;
                    }
                } 

                if (0 != (this.compiler.flags & QueryCompilerFlags.InverseQuery)) 
                { 
                    this.codeBlock.Append(new NumberIntervalOpcode(literal, expr.Op));
                } 
                else
                {
                    this.codeBlock.Append(new NumberRelationOpcode(literal, expr.Op));
                } 
            }
 
            void CompilePath(XPathExpr expr) 
            {
                DiagnosticUtility.DebugAssert(expr.SubExprCount == 2 || expr.SubExprCount == 3, ""); 

                if(expr.Type == XPathExprType.Filter)
                {
                    this.CompileFilter(expr.SubExpr[0]); 
                }
                else 
                { 
                    this.CompileExpression(expr.SubExpr[0]);
                    if(expr.SubExpr[0].ReturnType == ValueDataType.Sequence) 
                    {
                        if(IsSpecialInternalFunction(expr.SubExpr[0]))
                        {
                            this.codeBlock.DetachLast(); 
                        }
                        else 
                        { 
                            this.codeBlock.Append(new MergeOpcode());
                            this.codeBlock.Append(new PopSequenceToSequenceStackOpcode()); 
                        }
                    }
                }
 
                if(expr.SubExprCount == 2)
                { 
                    this.CompileRelativePath(expr.SubExpr[1], false); 
                }
                else if(expr.SubExprCount == 3) 
                {
                    // Compile the step
                    XPathExpr e = expr.SubExpr[1];
                    DiagnosticUtility.DebugAssert(XPathExprType.PathStep == e.Type, ""); 

                    XPathStepExpr step = (XPathStepExpr) e; 
                    DiagnosticUtility.DebugAssert(QueryNodeType.Root != step.SelectDesc.Type, ""); 

                    if (!step.SelectDesc.Axis.IsSupported()) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.UnsupportedAxis));
                    }
 
                    this.codeBlock.Append(new SelectOpcode(step.SelectDesc));
 
                    // The step may have predicates.. 
                    if (step.SubExprCount > 0)
                    { 
                        this.compiler.nestingLevel++;
                        if(this.compiler.nestingLevel > 3) // throw if we find something deepter than [ [ ] ]
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep)); 
                        }
                        this.CompilePredicates(step.SubExpr); 
                        this.compiler.nestingLevel--; 
                    }
 
                    // Compile the relative path
                    this.CompileRelativePath(expr.SubExpr[2], false);
                }
            } 

            void CompilePredicate(XPathExpr expr) 
            { 
                // If the expression does not return a boolean, introduce a typecast
                // If the predicate expression is a standalone number literal, interpret it as a literal 
                if (expr.IsLiteral && XPathExprType.Number == expr.Type)
                {
                    this.CompileLiteralOrdinal(expr);
                } 
                else
                { 
                    this.CompileExpression(expr); 
                    if (expr.ReturnType == ValueDataType.Double)
                    { 
                        this.codeBlock.Append(new OrdinalOpcode());
                    }
                    else if (expr.ReturnType != ValueDataType.Boolean)
                    { 
                        this.CompileTypecast(ValueDataType.Boolean);
                    } 
                } 
                // Apply the results of the predicate on the context sequence
                this.codeBlock.Append(new ApplyFilterOpcode()); 
            }

            void CompilePredicates(XPathExprList exprList)
            { 
                // Compile each predicate expression first
                for (int i = 0; i < exprList.Count; ++i) 
                { 
                    this.CompilePredicate(exprList[i]);
                } 
            }

            void CompileRelational(XPathRelationExpr expr)
            { 
                // Are we comparing two literals?
                if (expr.Left.IsLiteral && expr.Right.IsLiteral) 
                { 
                    // Do the comparison at compile time
                    this.CompileLiteralRelation(expr); 
                    return;
                }

                // != is not optimized in M5 
                if (expr.Op != RelationOperator.Ne)
                { 
                    // Number relations are handled in a special way 
                    if (XPathExprType.Number == expr.Left.Type || XPathExprType.Number == expr.Right.Type)
                    { 
                        this.CompileNumberRelation(expr);
                        return;
                    }
 
                    // Equality tests with string literals are handled in a special way
                    if (expr.Op == RelationOperator.Eq && (XPathExprType.String == expr.Left.Type || XPathExprType.String == expr.Right.Type)) 
                    { 
                        this.CompileStringLiteralEquality(expr);
                        return; 
                    }
                }

                // Can't optimize. Use a general purpose relation opcode 
                this.CompileExpression(expr.Left);
                this.CompileExpression(expr.Right); 
                this.codeBlock.Append(new RelationOpcode(expr.Op)); 
            }
 
            void CompileRelativePath(XPathExpr expr, bool start)
            {
                DiagnosticUtility.DebugAssert(XPathExprType.RelativePath == expr.Type, "");
                this.CompileSteps(expr.SubExpr, start); 
                // Step complete. Transfer results onto the value stack
                this.codeBlock.Append(new PopSequenceToValueStackOpcode()); 
            } 

            void CompileStringLiteralEquality(XPathRelationExpr expr) 
            {
                DiagnosticUtility.DebugAssert(expr.Op == RelationOperator.Eq, "");

                bool leftString = (XPathExprType.String == expr.Left.Type); 
                bool rightString = (XPathExprType.String == expr.Right.Type);
 
                DiagnosticUtility.DebugAssert(leftString || rightString, ""); 
                DiagnosticUtility.DebugAssert(!(leftString && rightString), "");
 
                this.CompileExpression(leftString ? expr.Right : expr.Left);
                string literal = leftString ? ((XPathStringExpr) expr.Left).String : ((XPathStringExpr) expr.Right).String;
                this.codeBlock.Append(new StringEqualsOpcode(literal));
            } 

            void CompileSteps(XPathExprList steps) 
            { 
                CompileSteps(steps, true);
            } 

            void CompileSteps(XPathExprList steps, bool start)
            {
                for (int i = 0; i < steps.Count; ++i) 
                {
                    DiagnosticUtility.DebugAssert(XPathExprType.PathStep == steps[i].Type, ""); 
                    XPathStepExpr step = (XPathStepExpr) steps[i]; 
                    if (!step.SelectDesc.Axis.IsSupported())
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.UnsupportedAxis));
                    }
                    Opcode stepOpcode = null;
                    if (start && 0 == i) 
                    {
                        // First steps 
                        // Is this an absolute path? We have an absolute path if the first step selects the root 
                        if (QueryNodeType.Root == step.SelectDesc.Type)
                        { 
                            stepOpcode = new SelectRootOpcode();
                        }
                        else
                        { 
                            stepOpcode = new InitialSelectOpcode(step.SelectDesc);
                        } 
                    } 
                    else
                    { 
                        DiagnosticUtility.DebugAssert(QueryNodeType.Root != step.SelectDesc.Type, "");
                        stepOpcode = new SelectOpcode(step.SelectDesc);
                    }
                    this.codeBlock.Append(stepOpcode); 
                    // The step may have predicates..
                    if (step.SubExprCount > 0) 
                    { 
                        this.compiler.nestingLevel++;
                        if(this.compiler.nestingLevel > 3) // throw if we find something deepter than [ [ ] ] 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(QueryCompileError.PredicateNestingTooDeep));
                        }
                        this.CompilePredicates(step.SubExpr); 
                        this.compiler.nestingLevel--;
                    } 
                } 
            }
 
            void CompileTypecast(ValueDataType destType)
            {
                DiagnosticUtility.DebugAssert(ValueDataType.None != destType, "");
                this.codeBlock.Append(new TypecastOpcode(destType)); 
            }
 
            void CompileXsltFunction(XPathXsltFunctionExpr expr) 
            {
                // Compile each argument expression first, introducing a typecast where appropriate 
                // Arguments are pushed C style - right to left
                if (expr.SubExprCount > 0)
                {
                    XPathExprList paramList = expr.SubExpr; 
                    for (int i = paramList.Count - 1; i >= 0; --i)
                    { 
                        XPathExpr param = paramList[i]; 
                        this.CompileExpression(param);
                        ValueDataType paramType = XPathXsltFunctionExpr.ConvertTypeFromXslt(expr.Function.ArgTypes[i]); 
                        if (ValueDataType.None != paramType)
                        {
                            if (param.ReturnType != paramType)
                            { 
                                this.CompileTypecast(paramType);
                            } 
                        } 
                    }
                } 

                if (expr.Function is XPathMessageFunction)
                {
                    this.codeBlock.Append(new XPathMessageFunctionCallOpcode((XPathMessageFunction)expr.Function, expr.SubExprCount)); 
                    if(IsSpecialInternalFunction(expr))
                    { 
                        this.codeBlock.Append(new PopSequenceToValueStackOpcode()); 
                    }
                } 
                else
                {
                    this.codeBlock.Append(new XsltFunctionCallOpcode(expr.Context, expr.Function, expr.SubExprCount));
                } 
            }
 
            void CompileXsltVariable(XPathXsltVariableExpr expr) 
            {
#if NO 
                // Remove this block if we never decide to use variables in an XPathMessageContext
                // It is here in case we decide to
                if (expr.Variable is XPathMessageVariable)
                { 
                    this.codeBlock.Append(new PushXPathMessageVariableOpcode((XPathMessageVariable)expr.Variable));
                } 
                else 
                {
                    this.codeBlock.Append(new PushXsltVariableOpcode(expr.Context, expr.Variable)); 
                }
#endif
                this.codeBlock.Append(new PushXsltVariableOpcode(expr.Context, expr.Variable));
            } 

            MathOpcode CreateMathOpcode(MathOperator op) 
            { 
                MathOpcode opcode = null;
                switch(op) 
                {
                    case MathOperator.None:
                        DiagnosticUtility.DebugAssert("");
                        break; 

                    case MathOperator.Plus: 
                        opcode = new PlusOpcode(); 
                        break;
                    case MathOperator.Minus: 
                        opcode = new MinusOpcode();
                        break;
                    case MathOperator.Div:
                        opcode = new DivideOpcode(); 
                        break;
                    case MathOperator.Multiply: 
                        opcode = new MultiplyOpcode(); 
                        break;
                    case MathOperator.Mod: 
                        opcode = new ModulusOpcode();
                        break;
                    case MathOperator.Negate:
                        opcode = new NegateOpcode(); 
                        break;
                } 
 
                return opcode;
            } 

            void NegateIfRequired(XPathExpr expr)
            {
                // We can combine these two since the flags they examine are set in exactly one (the same) place. 
                TypecastIfRequired(expr);
                if(expr.Negate) 
                { 
                    expr.Negate = false;
                    this.codeBlock.Append(new NegateOpcode()); 
                }
            }

            void TypecastIfRequired(XPathExpr expr) 
            {
                if(expr.TypecastRequired) 
                { 
                    expr.TypecastRequired = false;
                    CompileTypecast(expr.ReturnType); 
                }
            }

            void ThrowError(QueryCompileError error) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new QueryCompileException(error)); 
            } 
        }
    } 
}

// 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