QilTypeChecker.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / QIL / QilTypeChecker.cs / 1305376 / QilTypeChecker.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Reflection;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl; 
using System.Xml.Xsl.Runtime;
 
namespace System.Xml.Xsl.Qil { 

    ///  
    /// This class performs two functions:
    ///   1. Infer XmlQueryType of Qil nodes (constant, from arguments, etc)
    ///   2. Validate the arguments of Qil nodes if DEBUG is defined
    ///  
    internal class QilTypeChecker {
 
        public QilTypeChecker() { 
        }
 
        public XmlQueryType Check(QilNode n) {
            #region AUTOGENERATED
            switch (n.NodeType) {
                case QilNodeType.QilExpression: return CheckQilExpression((QilExpression)n); 
                case QilNodeType.FunctionList: return CheckFunctionList((QilList)n);
                case QilNodeType.GlobalVariableList: return CheckGlobalVariableList((QilList)n); 
                case QilNodeType.GlobalParameterList: return CheckGlobalParameterList((QilList)n); 
                case QilNodeType.ActualParameterList: return CheckActualParameterList((QilList)n);
                case QilNodeType.FormalParameterList: return CheckFormalParameterList((QilList)n); 
                case QilNodeType.SortKeyList: return CheckSortKeyList((QilList)n);
                case QilNodeType.BranchList: return CheckBranchList((QilList)n);
                case QilNodeType.OptimizeBarrier: return CheckOptimizeBarrier((QilUnary)n);
                case QilNodeType.Unknown: return CheckUnknown(n); 

                case QilNodeType.DataSource: return CheckDataSource((QilDataSource)n); 
                case QilNodeType.Nop: return CheckNop((QilUnary)n); 
                case QilNodeType.Error: return CheckError((QilUnary)n);
                case QilNodeType.Warning: return CheckWarning((QilUnary)n); 

                case QilNodeType.For: return CheckFor((QilIterator)n);
                case QilNodeType.Let: return CheckLet((QilIterator)n);
                case QilNodeType.Parameter: return CheckParameter((QilParameter)n); 
                case QilNodeType.PositionOf: return CheckPositionOf((QilUnary)n);
 
                case QilNodeType.True: return CheckTrue(n); 
                case QilNodeType.False: return CheckFalse(n);
                case QilNodeType.LiteralString: return CheckLiteralString((QilLiteral)n); 
                case QilNodeType.LiteralInt32: return CheckLiteralInt32((QilLiteral)n);
                case QilNodeType.LiteralInt64: return CheckLiteralInt64((QilLiteral)n);
                case QilNodeType.LiteralDouble: return CheckLiteralDouble((QilLiteral)n);
                case QilNodeType.LiteralDecimal: return CheckLiteralDecimal((QilLiteral)n); 
                case QilNodeType.LiteralQName: return CheckLiteralQName((QilName)n);
                case QilNodeType.LiteralType: return CheckLiteralType((QilLiteral)n); 
                case QilNodeType.LiteralObject: return CheckLiteralObject((QilLiteral)n); 

                case QilNodeType.And: return CheckAnd((QilBinary)n); 
                case QilNodeType.Or: return CheckOr((QilBinary)n);
                case QilNodeType.Not: return CheckNot((QilUnary)n);

                case QilNodeType.Conditional: return CheckConditional((QilTernary)n); 
                case QilNodeType.Choice: return CheckChoice((QilChoice)n);
 
                case QilNodeType.Length: return CheckLength((QilUnary)n); 
                case QilNodeType.Sequence: return CheckSequence((QilList)n);
                case QilNodeType.Union: return CheckUnion((QilBinary)n); 
                case QilNodeType.Intersection: return CheckIntersection((QilBinary)n);
                case QilNodeType.Difference: return CheckDifference((QilBinary)n);
                case QilNodeType.Average: return CheckAverage((QilUnary)n);
                case QilNodeType.Sum: return CheckSum((QilUnary)n); 
                case QilNodeType.Minimum: return CheckMinimum((QilUnary)n);
                case QilNodeType.Maximum: return CheckMaximum((QilUnary)n); 
 
                case QilNodeType.Negate: return CheckNegate((QilUnary)n);
                case QilNodeType.Add: return CheckAdd((QilBinary)n); 
                case QilNodeType.Subtract: return CheckSubtract((QilBinary)n);
                case QilNodeType.Multiply: return CheckMultiply((QilBinary)n);
                case QilNodeType.Divide: return CheckDivide((QilBinary)n);
                case QilNodeType.Modulo: return CheckModulo((QilBinary)n); 

                case QilNodeType.StrLength: return CheckStrLength((QilUnary)n); 
                case QilNodeType.StrConcat: return CheckStrConcat((QilStrConcat)n); 
                case QilNodeType.StrParseQName: return CheckStrParseQName((QilBinary)n);
 
                case QilNodeType.Ne: return CheckNe((QilBinary)n);
                case QilNodeType.Eq: return CheckEq((QilBinary)n);
                case QilNodeType.Gt: return CheckGt((QilBinary)n);
                case QilNodeType.Ge: return CheckGe((QilBinary)n); 
                case QilNodeType.Lt: return CheckLt((QilBinary)n);
                case QilNodeType.Le: return CheckLe((QilBinary)n); 
 
                case QilNodeType.Is: return CheckIs((QilBinary)n);
                case QilNodeType.After: return CheckAfter((QilBinary)n); 
                case QilNodeType.Before: return CheckBefore((QilBinary)n);

                case QilNodeType.Loop: return CheckLoop((QilLoop)n);
                case QilNodeType.Filter: return CheckFilter((QilLoop)n); 

                case QilNodeType.Sort: return CheckSort((QilLoop)n); 
                case QilNodeType.SortKey: return CheckSortKey((QilSortKey)n); 
                case QilNodeType.DocOrderDistinct: return CheckDocOrderDistinct((QilUnary)n);
 
                case QilNodeType.Function: return CheckFunction((QilFunction)n);
                case QilNodeType.Invoke: return CheckInvoke((QilInvoke)n);

                case QilNodeType.Content: return CheckContent((QilUnary)n); 
                case QilNodeType.Attribute: return CheckAttribute((QilBinary)n);
                case QilNodeType.Parent: return CheckParent((QilUnary)n); 
                case QilNodeType.Root: return CheckRoot((QilUnary)n); 
                case QilNodeType.XmlContext: return CheckXmlContext(n);
                case QilNodeType.Descendant: return CheckDescendant((QilUnary)n); 
                case QilNodeType.DescendantOrSelf: return CheckDescendantOrSelf((QilUnary)n);
                case QilNodeType.Ancestor: return CheckAncestor((QilUnary)n);
                case QilNodeType.AncestorOrSelf: return CheckAncestorOrSelf((QilUnary)n);
                case QilNodeType.Preceding: return CheckPreceding((QilUnary)n); 
                case QilNodeType.FollowingSibling: return CheckFollowingSibling((QilUnary)n);
                case QilNodeType.PrecedingSibling: return CheckPrecedingSibling((QilUnary)n); 
                case QilNodeType.NodeRange: return CheckNodeRange((QilBinary)n); 
                case QilNodeType.Deref: return CheckDeref((QilBinary)n);
 
                case QilNodeType.ElementCtor: return CheckElementCtor((QilBinary)n);
                case QilNodeType.AttributeCtor: return CheckAttributeCtor((QilBinary)n);
                case QilNodeType.CommentCtor: return CheckCommentCtor((QilUnary)n);
                case QilNodeType.PICtor: return CheckPICtor((QilBinary)n); 
                case QilNodeType.TextCtor: return CheckTextCtor((QilUnary)n);
                case QilNodeType.RawTextCtor: return CheckRawTextCtor((QilUnary)n); 
                case QilNodeType.DocumentCtor: return CheckDocumentCtor((QilUnary)n); 
                case QilNodeType.NamespaceDecl: return CheckNamespaceDecl((QilBinary)n);
                case QilNodeType.RtfCtor: return CheckRtfCtor((QilBinary)n); 

                case QilNodeType.NameOf: return CheckNameOf((QilUnary)n);
                case QilNodeType.LocalNameOf: return CheckLocalNameOf((QilUnary)n);
                case QilNodeType.NamespaceUriOf: return CheckNamespaceUriOf((QilUnary)n); 
                case QilNodeType.PrefixOf: return CheckPrefixOf((QilUnary)n);
 
                case QilNodeType.TypeAssert: return CheckTypeAssert((QilTargetType)n); 
                case QilNodeType.IsType: return CheckIsType((QilTargetType)n);
                case QilNodeType.IsEmpty: return CheckIsEmpty((QilUnary)n); 

                case QilNodeType.XPathNodeValue: return CheckXPathNodeValue((QilUnary)n);
                case QilNodeType.XPathFollowing: return CheckXPathFollowing((QilUnary)n);
                case QilNodeType.XPathPreceding: return CheckXPathPreceding((QilUnary)n); 
                case QilNodeType.XPathNamespace: return CheckXPathNamespace((QilUnary)n);
 
                case QilNodeType.XsltGenerateId: return CheckXsltGenerateId((QilUnary)n); 
                case QilNodeType.XsltInvokeLateBound: return CheckXsltInvokeLateBound((QilInvokeLateBound)n);
                case QilNodeType.XsltInvokeEarlyBound: return CheckXsltInvokeEarlyBound((QilInvokeEarlyBound)n); 
                case QilNodeType.XsltCopy: return CheckXsltCopy((QilBinary)n);
                case QilNodeType.XsltCopyOf: return CheckXsltCopyOf((QilUnary)n);
                case QilNodeType.XsltConvert: return CheckXsltConvert((QilTargetType)n);
 
                default: return CheckUnknown(n);
            } 
            #endregion 
        }
 
        #region meta
        //-----------------------------------------------
        // meta
        //----------------------------------------------- 
        public XmlQueryType CheckQilExpression(QilExpression node) {
            Check(node[0].NodeType == QilNodeType.False || node[0].NodeType == QilNodeType.True, node, "IsDebug must either be True or False"); 
            CheckLiteralValue(node[1], typeof(XmlWriterSettings)); 
            CheckLiteralValue(node[2], typeof(IList));
            CheckClassAndNodeType(node[3], typeof(QilList), QilNodeType.GlobalParameterList); 
            CheckClassAndNodeType(node[4], typeof(QilList), QilNodeType.GlobalVariableList);
            CheckLiteralValue(node[5], typeof(IList));
            CheckClassAndNodeType(node[6], typeof(QilList), QilNodeType.FunctionList);
            return XmlQueryTypeFactory.ItemS; 
        }
 
        public XmlQueryType CheckFunctionList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilFunction), QilNodeType.Function); 
            return node.XmlType;
        }

        public XmlQueryType CheckGlobalVariableList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilIterator), QilNodeType.Let); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckGlobalParameterList(QilList node) {
            foreach (QilNode child in node) {
                CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter);
                Check(((QilParameter)child).Name != null, child, "Global parameter's name is null"); 
            }
            return node.XmlType; 
        } 

        public XmlQueryType CheckActualParameterList(QilList node) { 
            return node.XmlType;
        }

        public XmlQueryType CheckFormalParameterList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckSortKeyList(QilList node) {
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilSortKey), QilNodeType.SortKey);
            return node.XmlType; 
        }
 
        public XmlQueryType CheckBranchList(QilList node) { 
            return node.XmlType;
        } 

        public XmlQueryType CheckOptimizeBarrier(QilUnary node) {
            return node.Child.XmlType;
        } 

        public XmlQueryType CheckUnknown(QilNode node) { 
            return node.XmlType; 
        }
 
        #endregion // meta

        #region specials
        //----------------------------------------------- 
        // specials
        //----------------------------------------------- 
        public XmlQueryType CheckDataSource(QilDataSource node) { 
            CheckXmlType(node.Name, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.BaseUri, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.NodeNotRtfQ;
        }

        public XmlQueryType CheckNop(QilUnary node) { 
            return node.Child.XmlType;
        } 
 
        public XmlQueryType CheckError(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.None;
        }

        public XmlQueryType CheckWarning(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
            return XmlQueryTypeFactory.Empty; 
        } 

        #endregion // specials 

        #region variables
        //-----------------------------------------------
        // variables 
        //-----------------------------------------------
        public XmlQueryType CheckFor(QilIterator node) { 
            return node.Binding.XmlType.Prime; 
        }
 
        public XmlQueryType CheckLet(QilIterator node) {
            return node.Binding.XmlType;
        }
 
        public XmlQueryType CheckParameter(QilParameter node) {
            Check(node.Binding == null || node.Binding.XmlType.IsSubtypeOf(node.XmlType), node, "Parameter binding's xml type must be a subtype of the parameter's type"); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckPositionOf(QilUnary node) {
            return XmlQueryTypeFactory.IntX;
        }
 
        #endregion // variables
 
        #region literals 
        //-----------------------------------------------
        // literals 
        //-----------------------------------------------
        public XmlQueryType CheckTrue(QilNode node) {
            return XmlQueryTypeFactory.BooleanX;
        } 

        public XmlQueryType CheckFalse(QilNode node) { 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        public XmlQueryType CheckLiteralString(QilLiteral node) {
            CheckLiteralValue(node, typeof(string));
            return XmlQueryTypeFactory.StringX;
        } 

        public XmlQueryType CheckLiteralInt32(QilLiteral node) { 
            CheckLiteralValue(node, typeof(int)); 
            return XmlQueryTypeFactory.IntX;
        } 

        public XmlQueryType CheckLiteralInt64(QilLiteral node) {
            CheckLiteralValue(node, typeof(long));
            return XmlQueryTypeFactory.IntegerX; 
        }
 
        public XmlQueryType CheckLiteralDouble(QilLiteral node) { 
            CheckLiteralValue(node, typeof(double));
            return XmlQueryTypeFactory.DoubleX; 
        }

        public XmlQueryType CheckLiteralDecimal(QilLiteral node) {
            CheckLiteralValue(node, typeof(decimal)); 
            return XmlQueryTypeFactory.DecimalX;
        } 
 
        public XmlQueryType CheckLiteralQName(QilName node) {
            CheckLiteralValue(node, typeof(QilName)); 
            //

            return XmlQueryTypeFactory.QNameX;
        } 

        public XmlQueryType CheckLiteralType(QilLiteral node) { 
            CheckLiteralValue(node, typeof(XmlQueryType)); 
            return (XmlQueryType) node;
        } 

        public XmlQueryType CheckLiteralObject(QilLiteral node) {
            Check(node.Value != null, node, "Literal value is null");
            return XmlQueryTypeFactory.ItemS; 
        }
 
        #endregion // literals 

        #region boolean operators 
        //-----------------------------------------------
        // boolean operators
        //-----------------------------------------------
        public XmlQueryType CheckAnd(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.BooleanX); 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        public XmlQueryType CheckOr(QilBinary node) {
            return CheckAnd(node);
        }
 
        public XmlQueryType CheckNot(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.BooleanX); 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        #endregion // boolean operators

        #region choice
        //----------------------------------------------- 
        // choice
        //----------------------------------------------- 
        public XmlQueryType CheckConditional(QilTernary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
            return XmlQueryTypeFactory.Choice(node.Center.XmlType, node.Right.XmlType); 
        }

        public XmlQueryType CheckChoice(QilChoice node) {
            CheckXmlType(node.Expression, XmlQueryTypeFactory.IntX); 
            CheckClassAndNodeType(node.Branches, typeof(QilList), QilNodeType.BranchList);
            Check(node.Branches.Count > 0, node, "Choice must have at least one branch"); 
            return node.Branches.XmlType; 
        }
 
        #endregion // choice

        #region collection operators
        //----------------------------------------------- 
        // collection operators
        //----------------------------------------------- 
        public XmlQueryType CheckLength(QilUnary node) { 
            return XmlQueryTypeFactory.IntX;
        } 

        public XmlQueryType CheckSequence(QilList node) {
            return node.XmlType;
        } 

        public XmlQueryType CheckUnion(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
            return DistinctType(XmlQueryTypeFactory.Sequence(node.Left.XmlType, node.Right.XmlType)); 
        }

        public XmlQueryType CheckIntersection(QilBinary node) {
            return CheckUnion(node); 
        }
 
        public XmlQueryType CheckDifference(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.AtMost(node.Left.XmlType, node.Left.XmlType.Cardinality);
        }

        public XmlQueryType CheckAverage(QilUnary node) { 
            XmlQueryType xmlType = node.Child.XmlType;
            CheckNumericXS(node.Child); 
            return XmlQueryTypeFactory.PrimeProduct(xmlType, xmlType.MaybeEmpty ? XmlQueryCardinality.ZeroOrOne : XmlQueryCardinality.One); 
        }
 
        public XmlQueryType CheckSum(QilUnary node) {
            return CheckAverage(node);
        }
 
        public XmlQueryType CheckMinimum(QilUnary node) {
            return CheckAverage(node); 
        } 

        public XmlQueryType CheckMaximum(QilUnary node) { 
            return CheckAverage(node);
        }

        #endregion // collection operators 

        #region arithmetic operators 
        //----------------------------------------------- 
        // arithmetic operators
        //----------------------------------------------- 
        public XmlQueryType CheckNegate(QilUnary node) {
            CheckNumericX(node.Child);
            return node.Child.XmlType;
        } 

        public XmlQueryType CheckAdd(QilBinary node) { 
            CheckNumericX(node.Left); 
            CheckNumericX(node.Right);
            CheckNotDisjoint(node); 
            return node.Left.XmlType.TypeCode == XmlTypeCode.None ? node.Right.XmlType : node.Left.XmlType;
        }

        public XmlQueryType CheckSubtract(QilBinary node) { 
            return CheckAdd(node);
        } 
 
        public XmlQueryType CheckMultiply(QilBinary node) {
            return CheckAdd(node); 
        }

        public XmlQueryType CheckDivide(QilBinary node) {
            return CheckAdd(node); 
        }
 
        public XmlQueryType CheckModulo(QilBinary node) { 
            return CheckAdd(node);
        } 

        #endregion // arithmetic operators

        #region string operators 
        //-----------------------------------------------
        // string operators 
        //----------------------------------------------- 
        public XmlQueryType CheckStrLength(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.IntX;
        }

        public XmlQueryType CheckStrConcat(QilStrConcat node) { 
            CheckXmlType(node.Delimiter, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Values, XmlQueryTypeFactory.StringXS); 
            return XmlQueryTypeFactory.StringX; 
        }
 
        public XmlQueryType CheckStrParseQName(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            Check(node.Right.XmlType.IsSubtypeOf(XmlQueryTypeFactory.StringX) || node.Right.XmlType.IsSubtypeOf(XmlQueryTypeFactory.NamespaceS),
                  node, "StrParseQName must take either a string or a list of namespace as its second argument"); 
            return XmlQueryTypeFactory.QNameX;
        } 
 
        #endregion // string operators
 
        #region value comparison operators
        //-----------------------------------------------
        // value comparison operators
        //----------------------------------------------- 
        public XmlQueryType CheckNe(QilBinary node) {
            CheckAtomicX(node.Left); 
            CheckAtomicX(node.Right); 
            CheckNotDisjoint(node);
            return XmlQueryTypeFactory.BooleanX; 
        }

        public XmlQueryType CheckEq(QilBinary node) {
            return CheckNe(node); 
        }
 
        public XmlQueryType CheckGt(QilBinary node) { 
            return CheckNe(node);
        } 

        public XmlQueryType CheckGe(QilBinary node) {
            return CheckNe(node);
        } 

        public XmlQueryType CheckLt(QilBinary node) { 
            return CheckNe(node); 
        }
 
        public XmlQueryType CheckLe(QilBinary node) {
            return CheckNe(node);
        }
 
        #endregion // value comparison operators
 
        #region node comparison operators 
        //-----------------------------------------------
        // node comparison operators 
        //-----------------------------------------------
        public XmlQueryType CheckIs(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.BooleanX;
        } 
 
        public XmlQueryType CheckAfter(QilBinary node) {
            return CheckIs(node); 
        }

        public XmlQueryType CheckBefore(QilBinary node) {
            return CheckIs(node); 
        }
 
        #endregion // node comparison operators 

        #region loops 
        //-----------------------------------------------
        // loops
        //-----------------------------------------------
        public XmlQueryType CheckLoop(QilLoop node) { 
            CheckClass(node[0], typeof(QilIterator));
            Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Loop variable must be a For or Let iterator"); 
 
            XmlQueryType bodyType = node.Body.XmlType;
            XmlQueryCardinality variableCard = node.Variable.NodeType == QilNodeType.Let ? XmlQueryCardinality.One : node.Variable.Binding.XmlType.Cardinality; 

            // Loops do not preserve DocOrderDistinct
            return XmlQueryTypeFactory.PrimeProduct(bodyType, variableCard * bodyType.Cardinality);
        } 

        public XmlQueryType CheckFilter(QilLoop node) { 
            CheckClass(node[0], typeof(QilIterator)); 
            Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Filter variable must be a For or Let iterator");
            CheckXmlType(node.Body, XmlQueryTypeFactory.BooleanX); 

            // Attempt to restrict filter's type by checking condition
            XmlQueryType filterType = FindFilterType(node.Variable, node.Body);
            if (filterType != null) 
                return filterType;
 
            return XmlQueryTypeFactory.AtMost(node.Variable.Binding.XmlType, node.Variable.Binding.XmlType.Cardinality); 
        }
 
        #endregion // loops

        #region sorting
        //----------------------------------------------- 
        // sorting
        //----------------------------------------------- 
        public XmlQueryType CheckSort(QilLoop node) { 
            XmlQueryType varType = node.Variable.Binding.XmlType;
 
            CheckClassAndNodeType(node[0], typeof(QilIterator), QilNodeType.For);
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.SortKeyList);

            // Sort does not preserve DocOrderDistinct 
            return XmlQueryTypeFactory.PrimeProduct(varType, varType.Cardinality);
        } 
 
        public XmlQueryType CheckSortKey(QilSortKey node) {
            CheckAtomicX(node.Key); 
            CheckXmlType(node.Collation, XmlQueryTypeFactory.StringX);
            return node.Key.XmlType;
        }
 
        public XmlQueryType CheckDocOrderDistinct(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS); 
            return DistinctType(node.Child.XmlType); 
        }
 
        #endregion // sorting

        #region function definition and invocation
        //----------------------------------------------- 
        // function definition and invocation
        //----------------------------------------------- 
        public XmlQueryType CheckFunction(QilFunction node) { 
            CheckClassAndNodeType(node[0], typeof(QilList), QilNodeType.FormalParameterList);
            Check(node[2].NodeType == QilNodeType.False || node[2].NodeType == QilNodeType.True, node, "SideEffects must either be True or False"); 
            Check(node.Definition.XmlType.IsSubtypeOf(node.XmlType), node, "Function definition's xml type must be a subtype of the function's return type");
            return node.XmlType;
        }
 
        public XmlQueryType CheckInvoke(QilInvoke node) {
        #if DEBUG 
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList); 

            QilList actualArgs = node.Arguments; 
            QilList formalArgs = node.Function.Arguments;
            Check(actualArgs.Count == formalArgs.Count, actualArgs, "Invoke argument count must match function's argument count");

            for (int i = 0; i < actualArgs.Count; i++) 
                Check(actualArgs[i].XmlType.IsSubtypeOf(formalArgs[i].XmlType), actualArgs[i], "Invoke argument must be a subtype of the invoked function's argument");
        #endif 
 
            return node.Function.XmlType;
        } 

        #endregion // function definition and invocation

        #region XML navigation 
        //-----------------------------------------------
        // XML navigation 
        //----------------------------------------------- 
        public XmlQueryType CheckContent(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.AttributeOrContentS;
        }

        public XmlQueryType CheckAttribute(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.QNameX); 
            return XmlQueryTypeFactory.AttributeQ; 
        }
 
        public XmlQueryType CheckParent(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.DocumentOrElementQ;
        } 

        public XmlQueryType CheckRoot(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.NodeNotRtf;
        } 

        public XmlQueryType CheckXmlContext(QilNode node) {
            return XmlQueryTypeFactory.NodeNotRtf;
        } 

        public XmlQueryType CheckDescendant(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.ContentS;
        } 

        public XmlQueryType CheckDescendantOrSelf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.ContentS); 
        }
 
        public XmlQueryType CheckAncestor(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.DocumentOrElementS; 
        }

        public XmlQueryType CheckAncestorOrSelf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.DocumentOrElementS);
        } 
 
        public XmlQueryType CheckPreceding(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.DocumentOrContentS;
        }

        public XmlQueryType CheckFollowingSibling(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS; 
        } 

        public XmlQueryType CheckPrecedingSibling(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS;
        }
 
        public XmlQueryType CheckNodeRange(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.Choice(node.Left.XmlType, XmlQueryTypeFactory.ContentS, node.Right.XmlType);
        } 

        public XmlQueryType CheckDeref(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.ElementS;
        } 
 
        #endregion // XML navigation
 
        #region XML construction
        //-----------------------------------------------
        // XML construction
        //----------------------------------------------- 
        public XmlQueryType CheckElementCtor(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.UntypedElement;
        } 

        public XmlQueryType CheckAttributeCtor(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.UntypedAttribute;
        } 
 
        public XmlQueryType CheckCommentCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.Comment;
        }

        public XmlQueryType CheckPICtor(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.PI; 
        }
 
        public XmlQueryType CheckTextCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
            return XmlQueryTypeFactory.Text;
        } 

        public XmlQueryType CheckRawTextCtor(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.Text;
        } 

        public XmlQueryType CheckDocumentCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
            return XmlQueryTypeFactory.UntypedDocument; 
        }
 
        public XmlQueryType CheckNamespaceDecl(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.Namespace;
        }

        public XmlQueryType CheckRtfCtor(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
            CheckClassAndNodeType(node.Right, typeof(QilLiteral), QilNodeType.LiteralString); 
            return XmlQueryTypeFactory.Node; 
        }
 
        #endregion // XML construction

        #region Node properties
        //----------------------------------------------- 
        // Node properties
        //----------------------------------------------- 
        public XmlQueryType CheckNameOf(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
            return XmlQueryTypeFactory.QNameX; 
        }

        public XmlQueryType CheckLocalNameOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 
            return XmlQueryTypeFactory.StringX;
        } 
 
        public XmlQueryType CheckNamespaceUriOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 
            return XmlQueryTypeFactory.StringX;
        }

        public XmlQueryType CheckPrefixOf(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
            return XmlQueryTypeFactory.StringX; 
        } 

        #endregion // Node properties 

        #region Copy operators
        //-----------------------------------------------
        // Copy operators 
        //-----------------------------------------------
        public XmlQueryType CheckDeepCopy(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return node.XmlType;
        } 

        #endregion // Copy operators

        #region Type operators 
        //-----------------------------------------------
        // Type operators 
        //----------------------------------------------- 
        public XmlQueryType CheckTypeAssert(QilTargetType node) {
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType); 
            return node.TargetType;
        }

        public XmlQueryType CheckIsType(QilTargetType node) { 
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType);
            return XmlQueryTypeFactory.BooleanX; 
        } 

        public XmlQueryType CheckIsEmpty(QilUnary node) { 
            return XmlQueryTypeFactory.BooleanX;
        }

        #endregion // Type operators 

        #region XPath operators 
        //----------------------------------------------- 
        // XPath operators
        //----------------------------------------------- 
        public XmlQueryType CheckXPathNodeValue(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeS);
            return XmlQueryTypeFactory.StringX;
        } 

        public XmlQueryType CheckXPathFollowing(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.ContentS;
        } 

        public XmlQueryType CheckXPathPreceding(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS; 
        }
 
        public XmlQueryType CheckXPathNamespace(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.NamespaceS; 
        }

        #endregion // XPath operators
 
        #region XSLT
        //----------------------------------------------- 
        // XSLT 
        //-----------------------------------------------
        public XmlQueryType CheckXsltGenerateId(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
            return XmlQueryTypeFactory.StringX;
        }
 
        public XmlQueryType CheckXsltInvokeLateBound(QilInvokeLateBound node) {
            CheckLiteralValue(node[0], typeof(QilName)); 
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList); 
            return XmlQueryTypeFactory.ItemS;
        } 

        public XmlQueryType CheckXsltInvokeEarlyBound(QilInvokeEarlyBound node) {
        #if DEBUG
            CheckLiteralValue(node[0], typeof(QilName)); 
            CheckLiteralValue(node[1], typeof(MethodInfo));
            CheckClassAndNodeType(node[2], typeof(QilList), QilNodeType.ActualParameterList); 
 
            XmlExtensionFunction extFunc = new XmlExtensionFunction(node.Name.LocalName, node.Name.NamespaceUri, node.ClrMethod);
            QilList actualArgs = node.Arguments; 
            Check(actualArgs.Count == extFunc.Method.GetParameters().Length, actualArgs, "InvokeEarlyBound argument count must match function's argument count");

            for (int i = 0; i < actualArgs.Count; i++) {
                Check(actualArgs[i].XmlType.IsSubtypeOf(extFunc.GetXmlArgumentType(i)), actualArgs[i], "InvokeEarlyBound argument must be a subtype of the invoked function's argument type"); 
            }
        #endif 
 
            return node.XmlType;
        } 

        public XmlQueryType CheckXsltCopy(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeS); 
            return XmlQueryTypeFactory.Choice(node.Left.XmlType, node.Right.XmlType);
        } 
 
        public XmlQueryType CheckXsltCopyOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 

            if ((node.Child.XmlType.NodeKinds & XmlNodeKindFlags.Document) != 0)
                return XmlQueryTypeFactory.NodeNotRtfS;
 
            return node.Child.XmlType;
        } 
 
        public XmlQueryType CheckXsltConvert(QilTargetType node) {
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType); 
            return node.TargetType;
        }
        #endregion // Xslt operators
 

        //----------------------------------------------- 
        // Helper functions 
        //-----------------------------------------------
 
        [Conditional("DEBUG")]
        private void Check(bool value, QilNode node, string message) {
            if (!value)
                QilValidationVisitor.SetError(node, message); 
        }
 
        [Conditional("DEBUG")] 
        private void CheckLiteralValue(QilNode node, Type clrTypeValue) {
            Check(node is QilLiteral, node, "Node must be instance of QilLiteral"); 

            Type clrType = ((QilLiteral) node).Value.GetType();
            Check(clrTypeValue.IsAssignableFrom(clrType), node, "Literal value must be of type " + clrTypeValue.Name);
        } 

        [Conditional("DEBUG")] 
        private void CheckClass(QilNode node, Type clrTypeClass) { 
            Check(clrTypeClass.IsAssignableFrom(node.GetType()), node, "Node must be instance of " + clrTypeClass.Name);
        } 

        [Conditional("DEBUG")]
        private void CheckClassAndNodeType(QilNode node, Type clrTypeClass, QilNodeType nodeType) {
            CheckClass(node, clrTypeClass); 
            Check(node.NodeType == nodeType, node, "Node must have QilNodeType." + nodeType);
        } 
 
        [Conditional("DEBUG")]
        private void CheckXmlType(QilNode node, XmlQueryType xmlType) { 
            Check(node.XmlType.IsSubtypeOf(xmlType), node, "Node's type " + node.XmlType + " is not a subtype of " + xmlType);
        }

        [Conditional("DEBUG")] 
        private void CheckNumericX(QilNode node) {
            Check(node.XmlType.IsNumeric && node.XmlType.IsSingleton && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict singleton numeric type"); 
        } 

        [Conditional("DEBUG")] 
        private void CheckNumericXS(QilNode node) {
            Check(node.XmlType.IsNumeric && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict numeric type");
        }
 
        [Conditional("DEBUG")]
        private void CheckAtomicX(QilNode node) { 
            Check(node.XmlType.IsAtomicValue && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict atomic value type"); 
        }
 
        [Conditional("DEBUG")]
        private void CheckNotDisjoint(QilBinary node) {
            Check(node.Left.XmlType.IsSubtypeOf(node.Right.XmlType) || node.Right.XmlType.IsSubtypeOf(node.Left.XmlType), node,
                  "Node must not have arguments with disjoint types " + node.Left.XmlType + " and " + node.Right.XmlType); 
        }
 
        private XmlQueryType DistinctType(XmlQueryType type) { 
            if (type.Cardinality == XmlQueryCardinality.More)
                return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.OneOrMore); 

            if (type.Cardinality == XmlQueryCardinality.NotOne)
                return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.ZeroOrMore);
 
            return type;
        } 
 
        private XmlQueryType FindFilterType(QilIterator variable, QilNode body) {
            XmlQueryType leftType; 
            QilBinary binary;

            if (body.XmlType.TypeCode == XmlTypeCode.None)
                return XmlQueryTypeFactory.None; 

            switch (body.NodeType) { 
                case QilNodeType.False: 
                    return XmlQueryTypeFactory.Empty;
 
                case QilNodeType.IsType:
                    // If testing the type of "variable", then filter type can be restricted
                    if ((object) ((QilTargetType) body).Source == (object) variable)
                        return XmlQueryTypeFactory.AtMost(((QilTargetType)body).TargetType, variable.Binding.XmlType.Cardinality); 
                    break;
 
                case QilNodeType.And: 
                    // Both And conditions can be used to restrict filter's type
                    leftType = FindFilterType(variable, ((QilBinary) body).Left); 
                    if (leftType != null)
                        return leftType;

                    return FindFilterType(variable, ((QilBinary) body).Right); 

                case QilNodeType.Eq: 
                    // Restrict cardinality if position($iterator) = $pos is found 
                    binary = (QilBinary) body;
                    if (binary.Left.NodeType == QilNodeType.PositionOf) { 
                        if ((object) ((QilUnary) binary.Left).Child == (object) variable)
                            return XmlQueryTypeFactory.AtMost(variable.Binding.XmlType, XmlQueryCardinality.ZeroOrOne);
                    }
                    break; 
            }
 
            return null; 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Reflection;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Xsl; 
using System.Xml.Xsl.Runtime;
 
namespace System.Xml.Xsl.Qil { 

    ///  
    /// This class performs two functions:
    ///   1. Infer XmlQueryType of Qil nodes (constant, from arguments, etc)
    ///   2. Validate the arguments of Qil nodes if DEBUG is defined
    ///  
    internal class QilTypeChecker {
 
        public QilTypeChecker() { 
        }
 
        public XmlQueryType Check(QilNode n) {
            #region AUTOGENERATED
            switch (n.NodeType) {
                case QilNodeType.QilExpression: return CheckQilExpression((QilExpression)n); 
                case QilNodeType.FunctionList: return CheckFunctionList((QilList)n);
                case QilNodeType.GlobalVariableList: return CheckGlobalVariableList((QilList)n); 
                case QilNodeType.GlobalParameterList: return CheckGlobalParameterList((QilList)n); 
                case QilNodeType.ActualParameterList: return CheckActualParameterList((QilList)n);
                case QilNodeType.FormalParameterList: return CheckFormalParameterList((QilList)n); 
                case QilNodeType.SortKeyList: return CheckSortKeyList((QilList)n);
                case QilNodeType.BranchList: return CheckBranchList((QilList)n);
                case QilNodeType.OptimizeBarrier: return CheckOptimizeBarrier((QilUnary)n);
                case QilNodeType.Unknown: return CheckUnknown(n); 

                case QilNodeType.DataSource: return CheckDataSource((QilDataSource)n); 
                case QilNodeType.Nop: return CheckNop((QilUnary)n); 
                case QilNodeType.Error: return CheckError((QilUnary)n);
                case QilNodeType.Warning: return CheckWarning((QilUnary)n); 

                case QilNodeType.For: return CheckFor((QilIterator)n);
                case QilNodeType.Let: return CheckLet((QilIterator)n);
                case QilNodeType.Parameter: return CheckParameter((QilParameter)n); 
                case QilNodeType.PositionOf: return CheckPositionOf((QilUnary)n);
 
                case QilNodeType.True: return CheckTrue(n); 
                case QilNodeType.False: return CheckFalse(n);
                case QilNodeType.LiteralString: return CheckLiteralString((QilLiteral)n); 
                case QilNodeType.LiteralInt32: return CheckLiteralInt32((QilLiteral)n);
                case QilNodeType.LiteralInt64: return CheckLiteralInt64((QilLiteral)n);
                case QilNodeType.LiteralDouble: return CheckLiteralDouble((QilLiteral)n);
                case QilNodeType.LiteralDecimal: return CheckLiteralDecimal((QilLiteral)n); 
                case QilNodeType.LiteralQName: return CheckLiteralQName((QilName)n);
                case QilNodeType.LiteralType: return CheckLiteralType((QilLiteral)n); 
                case QilNodeType.LiteralObject: return CheckLiteralObject((QilLiteral)n); 

                case QilNodeType.And: return CheckAnd((QilBinary)n); 
                case QilNodeType.Or: return CheckOr((QilBinary)n);
                case QilNodeType.Not: return CheckNot((QilUnary)n);

                case QilNodeType.Conditional: return CheckConditional((QilTernary)n); 
                case QilNodeType.Choice: return CheckChoice((QilChoice)n);
 
                case QilNodeType.Length: return CheckLength((QilUnary)n); 
                case QilNodeType.Sequence: return CheckSequence((QilList)n);
                case QilNodeType.Union: return CheckUnion((QilBinary)n); 
                case QilNodeType.Intersection: return CheckIntersection((QilBinary)n);
                case QilNodeType.Difference: return CheckDifference((QilBinary)n);
                case QilNodeType.Average: return CheckAverage((QilUnary)n);
                case QilNodeType.Sum: return CheckSum((QilUnary)n); 
                case QilNodeType.Minimum: return CheckMinimum((QilUnary)n);
                case QilNodeType.Maximum: return CheckMaximum((QilUnary)n); 
 
                case QilNodeType.Negate: return CheckNegate((QilUnary)n);
                case QilNodeType.Add: return CheckAdd((QilBinary)n); 
                case QilNodeType.Subtract: return CheckSubtract((QilBinary)n);
                case QilNodeType.Multiply: return CheckMultiply((QilBinary)n);
                case QilNodeType.Divide: return CheckDivide((QilBinary)n);
                case QilNodeType.Modulo: return CheckModulo((QilBinary)n); 

                case QilNodeType.StrLength: return CheckStrLength((QilUnary)n); 
                case QilNodeType.StrConcat: return CheckStrConcat((QilStrConcat)n); 
                case QilNodeType.StrParseQName: return CheckStrParseQName((QilBinary)n);
 
                case QilNodeType.Ne: return CheckNe((QilBinary)n);
                case QilNodeType.Eq: return CheckEq((QilBinary)n);
                case QilNodeType.Gt: return CheckGt((QilBinary)n);
                case QilNodeType.Ge: return CheckGe((QilBinary)n); 
                case QilNodeType.Lt: return CheckLt((QilBinary)n);
                case QilNodeType.Le: return CheckLe((QilBinary)n); 
 
                case QilNodeType.Is: return CheckIs((QilBinary)n);
                case QilNodeType.After: return CheckAfter((QilBinary)n); 
                case QilNodeType.Before: return CheckBefore((QilBinary)n);

                case QilNodeType.Loop: return CheckLoop((QilLoop)n);
                case QilNodeType.Filter: return CheckFilter((QilLoop)n); 

                case QilNodeType.Sort: return CheckSort((QilLoop)n); 
                case QilNodeType.SortKey: return CheckSortKey((QilSortKey)n); 
                case QilNodeType.DocOrderDistinct: return CheckDocOrderDistinct((QilUnary)n);
 
                case QilNodeType.Function: return CheckFunction((QilFunction)n);
                case QilNodeType.Invoke: return CheckInvoke((QilInvoke)n);

                case QilNodeType.Content: return CheckContent((QilUnary)n); 
                case QilNodeType.Attribute: return CheckAttribute((QilBinary)n);
                case QilNodeType.Parent: return CheckParent((QilUnary)n); 
                case QilNodeType.Root: return CheckRoot((QilUnary)n); 
                case QilNodeType.XmlContext: return CheckXmlContext(n);
                case QilNodeType.Descendant: return CheckDescendant((QilUnary)n); 
                case QilNodeType.DescendantOrSelf: return CheckDescendantOrSelf((QilUnary)n);
                case QilNodeType.Ancestor: return CheckAncestor((QilUnary)n);
                case QilNodeType.AncestorOrSelf: return CheckAncestorOrSelf((QilUnary)n);
                case QilNodeType.Preceding: return CheckPreceding((QilUnary)n); 
                case QilNodeType.FollowingSibling: return CheckFollowingSibling((QilUnary)n);
                case QilNodeType.PrecedingSibling: return CheckPrecedingSibling((QilUnary)n); 
                case QilNodeType.NodeRange: return CheckNodeRange((QilBinary)n); 
                case QilNodeType.Deref: return CheckDeref((QilBinary)n);
 
                case QilNodeType.ElementCtor: return CheckElementCtor((QilBinary)n);
                case QilNodeType.AttributeCtor: return CheckAttributeCtor((QilBinary)n);
                case QilNodeType.CommentCtor: return CheckCommentCtor((QilUnary)n);
                case QilNodeType.PICtor: return CheckPICtor((QilBinary)n); 
                case QilNodeType.TextCtor: return CheckTextCtor((QilUnary)n);
                case QilNodeType.RawTextCtor: return CheckRawTextCtor((QilUnary)n); 
                case QilNodeType.DocumentCtor: return CheckDocumentCtor((QilUnary)n); 
                case QilNodeType.NamespaceDecl: return CheckNamespaceDecl((QilBinary)n);
                case QilNodeType.RtfCtor: return CheckRtfCtor((QilBinary)n); 

                case QilNodeType.NameOf: return CheckNameOf((QilUnary)n);
                case QilNodeType.LocalNameOf: return CheckLocalNameOf((QilUnary)n);
                case QilNodeType.NamespaceUriOf: return CheckNamespaceUriOf((QilUnary)n); 
                case QilNodeType.PrefixOf: return CheckPrefixOf((QilUnary)n);
 
                case QilNodeType.TypeAssert: return CheckTypeAssert((QilTargetType)n); 
                case QilNodeType.IsType: return CheckIsType((QilTargetType)n);
                case QilNodeType.IsEmpty: return CheckIsEmpty((QilUnary)n); 

                case QilNodeType.XPathNodeValue: return CheckXPathNodeValue((QilUnary)n);
                case QilNodeType.XPathFollowing: return CheckXPathFollowing((QilUnary)n);
                case QilNodeType.XPathPreceding: return CheckXPathPreceding((QilUnary)n); 
                case QilNodeType.XPathNamespace: return CheckXPathNamespace((QilUnary)n);
 
                case QilNodeType.XsltGenerateId: return CheckXsltGenerateId((QilUnary)n); 
                case QilNodeType.XsltInvokeLateBound: return CheckXsltInvokeLateBound((QilInvokeLateBound)n);
                case QilNodeType.XsltInvokeEarlyBound: return CheckXsltInvokeEarlyBound((QilInvokeEarlyBound)n); 
                case QilNodeType.XsltCopy: return CheckXsltCopy((QilBinary)n);
                case QilNodeType.XsltCopyOf: return CheckXsltCopyOf((QilUnary)n);
                case QilNodeType.XsltConvert: return CheckXsltConvert((QilTargetType)n);
 
                default: return CheckUnknown(n);
            } 
            #endregion 
        }
 
        #region meta
        //-----------------------------------------------
        // meta
        //----------------------------------------------- 
        public XmlQueryType CheckQilExpression(QilExpression node) {
            Check(node[0].NodeType == QilNodeType.False || node[0].NodeType == QilNodeType.True, node, "IsDebug must either be True or False"); 
            CheckLiteralValue(node[1], typeof(XmlWriterSettings)); 
            CheckLiteralValue(node[2], typeof(IList));
            CheckClassAndNodeType(node[3], typeof(QilList), QilNodeType.GlobalParameterList); 
            CheckClassAndNodeType(node[4], typeof(QilList), QilNodeType.GlobalVariableList);
            CheckLiteralValue(node[5], typeof(IList));
            CheckClassAndNodeType(node[6], typeof(QilList), QilNodeType.FunctionList);
            return XmlQueryTypeFactory.ItemS; 
        }
 
        public XmlQueryType CheckFunctionList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilFunction), QilNodeType.Function); 
            return node.XmlType;
        }

        public XmlQueryType CheckGlobalVariableList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilIterator), QilNodeType.Let); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckGlobalParameterList(QilList node) {
            foreach (QilNode child in node) {
                CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter);
                Check(((QilParameter)child).Name != null, child, "Global parameter's name is null"); 
            }
            return node.XmlType; 
        } 

        public XmlQueryType CheckActualParameterList(QilList node) { 
            return node.XmlType;
        }

        public XmlQueryType CheckFormalParameterList(QilList node) { 
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckSortKeyList(QilList node) {
            foreach (QilNode child in node)
                CheckClassAndNodeType(child, typeof(QilSortKey), QilNodeType.SortKey);
            return node.XmlType; 
        }
 
        public XmlQueryType CheckBranchList(QilList node) { 
            return node.XmlType;
        } 

        public XmlQueryType CheckOptimizeBarrier(QilUnary node) {
            return node.Child.XmlType;
        } 

        public XmlQueryType CheckUnknown(QilNode node) { 
            return node.XmlType; 
        }
 
        #endregion // meta

        #region specials
        //----------------------------------------------- 
        // specials
        //----------------------------------------------- 
        public XmlQueryType CheckDataSource(QilDataSource node) { 
            CheckXmlType(node.Name, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.BaseUri, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.NodeNotRtfQ;
        }

        public XmlQueryType CheckNop(QilUnary node) { 
            return node.Child.XmlType;
        } 
 
        public XmlQueryType CheckError(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.None;
        }

        public XmlQueryType CheckWarning(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
            return XmlQueryTypeFactory.Empty; 
        } 

        #endregion // specials 

        #region variables
        //-----------------------------------------------
        // variables 
        //-----------------------------------------------
        public XmlQueryType CheckFor(QilIterator node) { 
            return node.Binding.XmlType.Prime; 
        }
 
        public XmlQueryType CheckLet(QilIterator node) {
            return node.Binding.XmlType;
        }
 
        public XmlQueryType CheckParameter(QilParameter node) {
            Check(node.Binding == null || node.Binding.XmlType.IsSubtypeOf(node.XmlType), node, "Parameter binding's xml type must be a subtype of the parameter's type"); 
            return node.XmlType; 
        }
 
        public XmlQueryType CheckPositionOf(QilUnary node) {
            return XmlQueryTypeFactory.IntX;
        }
 
        #endregion // variables
 
        #region literals 
        //-----------------------------------------------
        // literals 
        //-----------------------------------------------
        public XmlQueryType CheckTrue(QilNode node) {
            return XmlQueryTypeFactory.BooleanX;
        } 

        public XmlQueryType CheckFalse(QilNode node) { 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        public XmlQueryType CheckLiteralString(QilLiteral node) {
            CheckLiteralValue(node, typeof(string));
            return XmlQueryTypeFactory.StringX;
        } 

        public XmlQueryType CheckLiteralInt32(QilLiteral node) { 
            CheckLiteralValue(node, typeof(int)); 
            return XmlQueryTypeFactory.IntX;
        } 

        public XmlQueryType CheckLiteralInt64(QilLiteral node) {
            CheckLiteralValue(node, typeof(long));
            return XmlQueryTypeFactory.IntegerX; 
        }
 
        public XmlQueryType CheckLiteralDouble(QilLiteral node) { 
            CheckLiteralValue(node, typeof(double));
            return XmlQueryTypeFactory.DoubleX; 
        }

        public XmlQueryType CheckLiteralDecimal(QilLiteral node) {
            CheckLiteralValue(node, typeof(decimal)); 
            return XmlQueryTypeFactory.DecimalX;
        } 
 
        public XmlQueryType CheckLiteralQName(QilName node) {
            CheckLiteralValue(node, typeof(QilName)); 
            //

            return XmlQueryTypeFactory.QNameX;
        } 

        public XmlQueryType CheckLiteralType(QilLiteral node) { 
            CheckLiteralValue(node, typeof(XmlQueryType)); 
            return (XmlQueryType) node;
        } 

        public XmlQueryType CheckLiteralObject(QilLiteral node) {
            Check(node.Value != null, node, "Literal value is null");
            return XmlQueryTypeFactory.ItemS; 
        }
 
        #endregion // literals 

        #region boolean operators 
        //-----------------------------------------------
        // boolean operators
        //-----------------------------------------------
        public XmlQueryType CheckAnd(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.BooleanX); 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        public XmlQueryType CheckOr(QilBinary node) {
            return CheckAnd(node);
        }
 
        public XmlQueryType CheckNot(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.BooleanX); 
            return XmlQueryTypeFactory.BooleanX; 
        }
 
        #endregion // boolean operators

        #region choice
        //----------------------------------------------- 
        // choice
        //----------------------------------------------- 
        public XmlQueryType CheckConditional(QilTernary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
            return XmlQueryTypeFactory.Choice(node.Center.XmlType, node.Right.XmlType); 
        }

        public XmlQueryType CheckChoice(QilChoice node) {
            CheckXmlType(node.Expression, XmlQueryTypeFactory.IntX); 
            CheckClassAndNodeType(node.Branches, typeof(QilList), QilNodeType.BranchList);
            Check(node.Branches.Count > 0, node, "Choice must have at least one branch"); 
            return node.Branches.XmlType; 
        }
 
        #endregion // choice

        #region collection operators
        //----------------------------------------------- 
        // collection operators
        //----------------------------------------------- 
        public XmlQueryType CheckLength(QilUnary node) { 
            return XmlQueryTypeFactory.IntX;
        } 

        public XmlQueryType CheckSequence(QilList node) {
            return node.XmlType;
        } 

        public XmlQueryType CheckUnion(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
            return DistinctType(XmlQueryTypeFactory.Sequence(node.Left.XmlType, node.Right.XmlType)); 
        }

        public XmlQueryType CheckIntersection(QilBinary node) {
            return CheckUnion(node); 
        }
 
        public XmlQueryType CheckDifference(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.AtMost(node.Left.XmlType, node.Left.XmlType.Cardinality);
        }

        public XmlQueryType CheckAverage(QilUnary node) { 
            XmlQueryType xmlType = node.Child.XmlType;
            CheckNumericXS(node.Child); 
            return XmlQueryTypeFactory.PrimeProduct(xmlType, xmlType.MaybeEmpty ? XmlQueryCardinality.ZeroOrOne : XmlQueryCardinality.One); 
        }
 
        public XmlQueryType CheckSum(QilUnary node) {
            return CheckAverage(node);
        }
 
        public XmlQueryType CheckMinimum(QilUnary node) {
            return CheckAverage(node); 
        } 

        public XmlQueryType CheckMaximum(QilUnary node) { 
            return CheckAverage(node);
        }

        #endregion // collection operators 

        #region arithmetic operators 
        //----------------------------------------------- 
        // arithmetic operators
        //----------------------------------------------- 
        public XmlQueryType CheckNegate(QilUnary node) {
            CheckNumericX(node.Child);
            return node.Child.XmlType;
        } 

        public XmlQueryType CheckAdd(QilBinary node) { 
            CheckNumericX(node.Left); 
            CheckNumericX(node.Right);
            CheckNotDisjoint(node); 
            return node.Left.XmlType.TypeCode == XmlTypeCode.None ? node.Right.XmlType : node.Left.XmlType;
        }

        public XmlQueryType CheckSubtract(QilBinary node) { 
            return CheckAdd(node);
        } 
 
        public XmlQueryType CheckMultiply(QilBinary node) {
            return CheckAdd(node); 
        }

        public XmlQueryType CheckDivide(QilBinary node) {
            return CheckAdd(node); 
        }
 
        public XmlQueryType CheckModulo(QilBinary node) { 
            return CheckAdd(node);
        } 

        #endregion // arithmetic operators

        #region string operators 
        //-----------------------------------------------
        // string operators 
        //----------------------------------------------- 
        public XmlQueryType CheckStrLength(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.IntX;
        }

        public XmlQueryType CheckStrConcat(QilStrConcat node) { 
            CheckXmlType(node.Delimiter, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Values, XmlQueryTypeFactory.StringXS); 
            return XmlQueryTypeFactory.StringX; 
        }
 
        public XmlQueryType CheckStrParseQName(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            Check(node.Right.XmlType.IsSubtypeOf(XmlQueryTypeFactory.StringX) || node.Right.XmlType.IsSubtypeOf(XmlQueryTypeFactory.NamespaceS),
                  node, "StrParseQName must take either a string or a list of namespace as its second argument"); 
            return XmlQueryTypeFactory.QNameX;
        } 
 
        #endregion // string operators
 
        #region value comparison operators
        //-----------------------------------------------
        // value comparison operators
        //----------------------------------------------- 
        public XmlQueryType CheckNe(QilBinary node) {
            CheckAtomicX(node.Left); 
            CheckAtomicX(node.Right); 
            CheckNotDisjoint(node);
            return XmlQueryTypeFactory.BooleanX; 
        }

        public XmlQueryType CheckEq(QilBinary node) {
            return CheckNe(node); 
        }
 
        public XmlQueryType CheckGt(QilBinary node) { 
            return CheckNe(node);
        } 

        public XmlQueryType CheckGe(QilBinary node) {
            return CheckNe(node);
        } 

        public XmlQueryType CheckLt(QilBinary node) { 
            return CheckNe(node); 
        }
 
        public XmlQueryType CheckLe(QilBinary node) {
            return CheckNe(node);
        }
 
        #endregion // value comparison operators
 
        #region node comparison operators 
        //-----------------------------------------------
        // node comparison operators 
        //-----------------------------------------------
        public XmlQueryType CheckIs(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.BooleanX;
        } 
 
        public XmlQueryType CheckAfter(QilBinary node) {
            return CheckIs(node); 
        }

        public XmlQueryType CheckBefore(QilBinary node) {
            return CheckIs(node); 
        }
 
        #endregion // node comparison operators 

        #region loops 
        //-----------------------------------------------
        // loops
        //-----------------------------------------------
        public XmlQueryType CheckLoop(QilLoop node) { 
            CheckClass(node[0], typeof(QilIterator));
            Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Loop variable must be a For or Let iterator"); 
 
            XmlQueryType bodyType = node.Body.XmlType;
            XmlQueryCardinality variableCard = node.Variable.NodeType == QilNodeType.Let ? XmlQueryCardinality.One : node.Variable.Binding.XmlType.Cardinality; 

            // Loops do not preserve DocOrderDistinct
            return XmlQueryTypeFactory.PrimeProduct(bodyType, variableCard * bodyType.Cardinality);
        } 

        public XmlQueryType CheckFilter(QilLoop node) { 
            CheckClass(node[0], typeof(QilIterator)); 
            Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Filter variable must be a For or Let iterator");
            CheckXmlType(node.Body, XmlQueryTypeFactory.BooleanX); 

            // Attempt to restrict filter's type by checking condition
            XmlQueryType filterType = FindFilterType(node.Variable, node.Body);
            if (filterType != null) 
                return filterType;
 
            return XmlQueryTypeFactory.AtMost(node.Variable.Binding.XmlType, node.Variable.Binding.XmlType.Cardinality); 
        }
 
        #endregion // loops

        #region sorting
        //----------------------------------------------- 
        // sorting
        //----------------------------------------------- 
        public XmlQueryType CheckSort(QilLoop node) { 
            XmlQueryType varType = node.Variable.Binding.XmlType;
 
            CheckClassAndNodeType(node[0], typeof(QilIterator), QilNodeType.For);
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.SortKeyList);

            // Sort does not preserve DocOrderDistinct 
            return XmlQueryTypeFactory.PrimeProduct(varType, varType.Cardinality);
        } 
 
        public XmlQueryType CheckSortKey(QilSortKey node) {
            CheckAtomicX(node.Key); 
            CheckXmlType(node.Collation, XmlQueryTypeFactory.StringX);
            return node.Key.XmlType;
        }
 
        public XmlQueryType CheckDocOrderDistinct(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS); 
            return DistinctType(node.Child.XmlType); 
        }
 
        #endregion // sorting

        #region function definition and invocation
        //----------------------------------------------- 
        // function definition and invocation
        //----------------------------------------------- 
        public XmlQueryType CheckFunction(QilFunction node) { 
            CheckClassAndNodeType(node[0], typeof(QilList), QilNodeType.FormalParameterList);
            Check(node[2].NodeType == QilNodeType.False || node[2].NodeType == QilNodeType.True, node, "SideEffects must either be True or False"); 
            Check(node.Definition.XmlType.IsSubtypeOf(node.XmlType), node, "Function definition's xml type must be a subtype of the function's return type");
            return node.XmlType;
        }
 
        public XmlQueryType CheckInvoke(QilInvoke node) {
        #if DEBUG 
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList); 

            QilList actualArgs = node.Arguments; 
            QilList formalArgs = node.Function.Arguments;
            Check(actualArgs.Count == formalArgs.Count, actualArgs, "Invoke argument count must match function's argument count");

            for (int i = 0; i < actualArgs.Count; i++) 
                Check(actualArgs[i].XmlType.IsSubtypeOf(formalArgs[i].XmlType), actualArgs[i], "Invoke argument must be a subtype of the invoked function's argument");
        #endif 
 
            return node.Function.XmlType;
        } 

        #endregion // function definition and invocation

        #region XML navigation 
        //-----------------------------------------------
        // XML navigation 
        //----------------------------------------------- 
        public XmlQueryType CheckContent(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.AttributeOrContentS;
        }

        public XmlQueryType CheckAttribute(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.QNameX); 
            return XmlQueryTypeFactory.AttributeQ; 
        }
 
        public XmlQueryType CheckParent(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.DocumentOrElementQ;
        } 

        public XmlQueryType CheckRoot(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.NodeNotRtf;
        } 

        public XmlQueryType CheckXmlContext(QilNode node) {
            return XmlQueryTypeFactory.NodeNotRtf;
        } 

        public XmlQueryType CheckDescendant(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.ContentS;
        } 

        public XmlQueryType CheckDescendantOrSelf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.ContentS); 
        }
 
        public XmlQueryType CheckAncestor(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.DocumentOrElementS; 
        }

        public XmlQueryType CheckAncestorOrSelf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.DocumentOrElementS);
        } 
 
        public XmlQueryType CheckPreceding(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.DocumentOrContentS;
        }

        public XmlQueryType CheckFollowingSibling(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS; 
        } 

        public XmlQueryType CheckPrecedingSibling(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS;
        }
 
        public XmlQueryType CheckNodeRange(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.Choice(node.Left.XmlType, XmlQueryTypeFactory.ContentS, node.Right.XmlType);
        } 

        public XmlQueryType CheckDeref(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.ElementS;
        } 
 
        #endregion // XML navigation
 
        #region XML construction
        //-----------------------------------------------
        // XML construction
        //----------------------------------------------- 
        public XmlQueryType CheckElementCtor(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX); 
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.UntypedElement;
        } 

        public XmlQueryType CheckAttributeCtor(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.UntypedAttribute;
        } 
 
        public XmlQueryType CheckCommentCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.Comment;
        }

        public XmlQueryType CheckPICtor(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS); 
            return XmlQueryTypeFactory.PI; 
        }
 
        public XmlQueryType CheckTextCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
            return XmlQueryTypeFactory.Text;
        } 

        public XmlQueryType CheckRawTextCtor(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.Text;
        } 

        public XmlQueryType CheckDocumentCtor(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
            return XmlQueryTypeFactory.UntypedDocument; 
        }
 
        public XmlQueryType CheckNamespaceDecl(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
            CheckXmlType(node.Right, XmlQueryTypeFactory.StringX); 
            return XmlQueryTypeFactory.Namespace;
        }

        public XmlQueryType CheckRtfCtor(QilBinary node) { 
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
            CheckClassAndNodeType(node.Right, typeof(QilLiteral), QilNodeType.LiteralString); 
            return XmlQueryTypeFactory.Node; 
        }
 
        #endregion // XML construction

        #region Node properties
        //----------------------------------------------- 
        // Node properties
        //----------------------------------------------- 
        public XmlQueryType CheckNameOf(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
            return XmlQueryTypeFactory.QNameX; 
        }

        public XmlQueryType CheckLocalNameOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 
            return XmlQueryTypeFactory.StringX;
        } 
 
        public XmlQueryType CheckNamespaceUriOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 
            return XmlQueryTypeFactory.StringX;
        }

        public XmlQueryType CheckPrefixOf(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
            return XmlQueryTypeFactory.StringX; 
        } 

        #endregion // Node properties 

        #region Copy operators
        //-----------------------------------------------
        // Copy operators 
        //-----------------------------------------------
        public XmlQueryType CheckDeepCopy(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return node.XmlType;
        } 

        #endregion // Copy operators

        #region Type operators 
        //-----------------------------------------------
        // Type operators 
        //----------------------------------------------- 
        public XmlQueryType CheckTypeAssert(QilTargetType node) {
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType); 
            return node.TargetType;
        }

        public XmlQueryType CheckIsType(QilTargetType node) { 
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType);
            return XmlQueryTypeFactory.BooleanX; 
        } 

        public XmlQueryType CheckIsEmpty(QilUnary node) { 
            return XmlQueryTypeFactory.BooleanX;
        }

        #endregion // Type operators 

        #region XPath operators 
        //----------------------------------------------- 
        // XPath operators
        //----------------------------------------------- 
        public XmlQueryType CheckXPathNodeValue(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeS);
            return XmlQueryTypeFactory.StringX;
        } 

        public XmlQueryType CheckXPathFollowing(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf); 
            return XmlQueryTypeFactory.ContentS;
        } 

        public XmlQueryType CheckXPathPreceding(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.ContentS; 
        }
 
        public XmlQueryType CheckXPathNamespace(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
            return XmlQueryTypeFactory.NamespaceS; 
        }

        #endregion // XPath operators
 
        #region XSLT
        //----------------------------------------------- 
        // XSLT 
        //-----------------------------------------------
        public XmlQueryType CheckXsltGenerateId(QilUnary node) { 
            CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
            return XmlQueryTypeFactory.StringX;
        }
 
        public XmlQueryType CheckXsltInvokeLateBound(QilInvokeLateBound node) {
            CheckLiteralValue(node[0], typeof(QilName)); 
            CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList); 
            return XmlQueryTypeFactory.ItemS;
        } 

        public XmlQueryType CheckXsltInvokeEarlyBound(QilInvokeEarlyBound node) {
        #if DEBUG
            CheckLiteralValue(node[0], typeof(QilName)); 
            CheckLiteralValue(node[1], typeof(MethodInfo));
            CheckClassAndNodeType(node[2], typeof(QilList), QilNodeType.ActualParameterList); 
 
            XmlExtensionFunction extFunc = new XmlExtensionFunction(node.Name.LocalName, node.Name.NamespaceUri, node.ClrMethod);
            QilList actualArgs = node.Arguments; 
            Check(actualArgs.Count == extFunc.Method.GetParameters().Length, actualArgs, "InvokeEarlyBound argument count must match function's argument count");

            for (int i = 0; i < actualArgs.Count; i++) {
                Check(actualArgs[i].XmlType.IsSubtypeOf(extFunc.GetXmlArgumentType(i)), actualArgs[i], "InvokeEarlyBound argument must be a subtype of the invoked function's argument type"); 
            }
        #endif 
 
            return node.XmlType;
        } 

        public XmlQueryType CheckXsltCopy(QilBinary node) {
            CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
            CheckXmlType(node.Right, XmlQueryTypeFactory.NodeS); 
            return XmlQueryTypeFactory.Choice(node.Left.XmlType, node.Right.XmlType);
        } 
 
        public XmlQueryType CheckXsltCopyOf(QilUnary node) {
            CheckXmlType(node.Child, XmlQueryTypeFactory.Node); 

            if ((node.Child.XmlType.NodeKinds & XmlNodeKindFlags.Document) != 0)
                return XmlQueryTypeFactory.NodeNotRtfS;
 
            return node.Child.XmlType;
        } 
 
        public XmlQueryType CheckXsltConvert(QilTargetType node) {
            CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType); 
            return node.TargetType;
        }
        #endregion // Xslt operators
 

        //----------------------------------------------- 
        // Helper functions 
        //-----------------------------------------------
 
        [Conditional("DEBUG")]
        private void Check(bool value, QilNode node, string message) {
            if (!value)
                QilValidationVisitor.SetError(node, message); 
        }
 
        [Conditional("DEBUG")] 
        private void CheckLiteralValue(QilNode node, Type clrTypeValue) {
            Check(node is QilLiteral, node, "Node must be instance of QilLiteral"); 

            Type clrType = ((QilLiteral) node).Value.GetType();
            Check(clrTypeValue.IsAssignableFrom(clrType), node, "Literal value must be of type " + clrTypeValue.Name);
        } 

        [Conditional("DEBUG")] 
        private void CheckClass(QilNode node, Type clrTypeClass) { 
            Check(clrTypeClass.IsAssignableFrom(node.GetType()), node, "Node must be instance of " + clrTypeClass.Name);
        } 

        [Conditional("DEBUG")]
        private void CheckClassAndNodeType(QilNode node, Type clrTypeClass, QilNodeType nodeType) {
            CheckClass(node, clrTypeClass); 
            Check(node.NodeType == nodeType, node, "Node must have QilNodeType." + nodeType);
        } 
 
        [Conditional("DEBUG")]
        private void CheckXmlType(QilNode node, XmlQueryType xmlType) { 
            Check(node.XmlType.IsSubtypeOf(xmlType), node, "Node's type " + node.XmlType + " is not a subtype of " + xmlType);
        }

        [Conditional("DEBUG")] 
        private void CheckNumericX(QilNode node) {
            Check(node.XmlType.IsNumeric && node.XmlType.IsSingleton && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict singleton numeric type"); 
        } 

        [Conditional("DEBUG")] 
        private void CheckNumericXS(QilNode node) {
            Check(node.XmlType.IsNumeric && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict numeric type");
        }
 
        [Conditional("DEBUG")]
        private void CheckAtomicX(QilNode node) { 
            Check(node.XmlType.IsAtomicValue && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict atomic value type"); 
        }
 
        [Conditional("DEBUG")]
        private void CheckNotDisjoint(QilBinary node) {
            Check(node.Left.XmlType.IsSubtypeOf(node.Right.XmlType) || node.Right.XmlType.IsSubtypeOf(node.Left.XmlType), node,
                  "Node must not have arguments with disjoint types " + node.Left.XmlType + " and " + node.Right.XmlType); 
        }
 
        private XmlQueryType DistinctType(XmlQueryType type) { 
            if (type.Cardinality == XmlQueryCardinality.More)
                return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.OneOrMore); 

            if (type.Cardinality == XmlQueryCardinality.NotOne)
                return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.ZeroOrMore);
 
            return type;
        } 
 
        private XmlQueryType FindFilterType(QilIterator variable, QilNode body) {
            XmlQueryType leftType; 
            QilBinary binary;

            if (body.XmlType.TypeCode == XmlTypeCode.None)
                return XmlQueryTypeFactory.None; 

            switch (body.NodeType) { 
                case QilNodeType.False: 
                    return XmlQueryTypeFactory.Empty;
 
                case QilNodeType.IsType:
                    // If testing the type of "variable", then filter type can be restricted
                    if ((object) ((QilTargetType) body).Source == (object) variable)
                        return XmlQueryTypeFactory.AtMost(((QilTargetType)body).TargetType, variable.Binding.XmlType.Cardinality); 
                    break;
 
                case QilNodeType.And: 
                    // Both And conditions can be used to restrict filter's type
                    leftType = FindFilterType(variable, ((QilBinary) body).Left); 
                    if (leftType != null)
                        return leftType;

                    return FindFilterType(variable, ((QilBinary) body).Right); 

                case QilNodeType.Eq: 
                    // Restrict cardinality if position($iterator) = $pos is found 
                    binary = (QilBinary) body;
                    if (binary.Left.NodeType == QilNodeType.PositionOf) { 
                        if ((object) ((QilUnary) binary.Left).Child == (object) variable)
                            return XmlQueryTypeFactory.AtMost(variable.Binding.XmlType, XmlQueryCardinality.ZeroOrOne);
                    }
                    break; 
            }
 
            return null; 
        }
    } 
}

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

                        

Link Menu

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