The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Qil \ QilTypeChecker

  1. //------------------------------------------------------------------------------
  2. // <copyright file="QilTypeChecker.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using System.Xml.Schema;
  21. using System.Xml.XPath;
  22. using System.Xml.Xsl;
  23. using System.Xml.Xsl.Runtime;
  24. namespace System.Xml.Xsl.Qil
  25. {
  26.    
  27.     /// <summary>
  28.     /// This class performs two functions:
  29.     /// 1. Infer XmlQueryType of Qil nodes (constant, from arguments, etc)
  30.     /// 2. Validate the arguments of Qil nodes if DEBUG is defined
  31.     /// </summary>
  32.     internal class QilTypeChecker
  33.     {
  34.        
  35.         public QilTypeChecker()
  36.         {
  37.         }
  38.        
  39.         public XmlQueryType Check(QilNode n)
  40.         {
  41.             #region AUTOGENERATED
  42.             switch (n.NodeType) {
  43.                 case QilNodeType.QilExpression:
  44.                     return CheckQilExpression((QilExpression)n);
  45.                 case QilNodeType.FunctionList:
  46.                     return CheckFunctionList((QilList)n);
  47.                 case QilNodeType.GlobalVariableList:
  48.                     return CheckGlobalVariableList((QilList)n);
  49.                 case QilNodeType.GlobalParameterList:
  50.                     return CheckGlobalParameterList((QilList)n);
  51.                 case QilNodeType.ActualParameterList:
  52.                     return CheckActualParameterList((QilList)n);
  53.                 case QilNodeType.FormalParameterList:
  54.                     return CheckFormalParameterList((QilList)n);
  55.                 case QilNodeType.SortKeyList:
  56.                     return CheckSortKeyList((QilList)n);
  57.                 case QilNodeType.BranchList:
  58.                     return CheckBranchList((QilList)n);
  59.                 case QilNodeType.OptimizeBarrier:
  60.                     return CheckOptimizeBarrier((QilUnary)n);
  61.                 case QilNodeType.Unknown:
  62.                     return CheckUnknown(n);
  63.                 case QilNodeType.DataSource:
  64.                    
  65.                     return CheckDataSource((QilDataSource)n);
  66.                 case QilNodeType.Nop:
  67.                     return CheckNop((QilUnary)n);
  68.                 case QilNodeType.Error:
  69.                     return CheckError((QilUnary)n);
  70.                 case QilNodeType.Warning:
  71.                     return CheckWarning((QilUnary)n);
  72.                 case QilNodeType.For:
  73.                    
  74.                     return CheckFor((QilIterator)n);
  75.                 case QilNodeType.Let:
  76.                     return CheckLet((QilIterator)n);
  77.                 case QilNodeType.Parameter:
  78.                     return CheckParameter((QilParameter)n);
  79.                 case QilNodeType.PositionOf:
  80.                     return CheckPositionOf((QilUnary)n);
  81.                 case QilNodeType.True:
  82.                    
  83.                     return CheckTrue(n);
  84.                 case QilNodeType.False:
  85.                     return CheckFalse(n);
  86.                 case QilNodeType.LiteralString:
  87.                     return CheckLiteralString((QilLiteral)n);
  88.                 case QilNodeType.LiteralInt32:
  89.                     return CheckLiteralInt32((QilLiteral)n);
  90.                 case QilNodeType.LiteralInt64:
  91.                     return CheckLiteralInt64((QilLiteral)n);
  92.                 case QilNodeType.LiteralDouble:
  93.                     return CheckLiteralDouble((QilLiteral)n);
  94.                 case QilNodeType.LiteralDecimal:
  95.                     return CheckLiteralDecimal((QilLiteral)n);
  96.                 case QilNodeType.LiteralQName:
  97.                     return CheckLiteralQName((QilName)n);
  98.                 case QilNodeType.LiteralType:
  99.                     return CheckLiteralType((QilLiteral)n);
  100.                 case QilNodeType.LiteralObject:
  101.                     return CheckLiteralObject((QilLiteral)n);
  102.                 case QilNodeType.And:
  103.                    
  104.                     return CheckAnd((QilBinary)n);
  105.                 case QilNodeType.Or:
  106.                     return CheckOr((QilBinary)n);
  107.                 case QilNodeType.Not:
  108.                     return CheckNot((QilUnary)n);
  109.                 case QilNodeType.Conditional:
  110.                    
  111.                     return CheckConditional((QilTernary)n);
  112.                 case QilNodeType.Choice:
  113.                     return CheckChoice((QilChoice)n);
  114.                 case QilNodeType.Length:
  115.                    
  116.                     return CheckLength((QilUnary)n);
  117.                 case QilNodeType.Sequence:
  118.                     return CheckSequence((QilList)n);
  119.                 case QilNodeType.Union:
  120.                     return CheckUnion((QilBinary)n);
  121.                 case QilNodeType.Intersection:
  122.                     return CheckIntersection((QilBinary)n);
  123.                 case QilNodeType.Difference:
  124.                     return CheckDifference((QilBinary)n);
  125.                 case QilNodeType.Average:
  126.                     return CheckAverage((QilUnary)n);
  127.                 case QilNodeType.Sum:
  128.                     return CheckSum((QilUnary)n);
  129.                 case QilNodeType.Minimum:
  130.                     return CheckMinimum((QilUnary)n);
  131.                 case QilNodeType.Maximum:
  132.                     return CheckMaximum((QilUnary)n);
  133.                 case QilNodeType.Negate:
  134.                    
  135.                     return CheckNegate((QilUnary)n);
  136.                 case QilNodeType.Add:
  137.                     return CheckAdd((QilBinary)n);
  138.                 case QilNodeType.Subtract:
  139.                     return CheckSubtract((QilBinary)n);
  140.                 case QilNodeType.Multiply:
  141.                     return CheckMultiply((QilBinary)n);
  142.                 case QilNodeType.Divide:
  143.                     return CheckDivide((QilBinary)n);
  144.                 case QilNodeType.Modulo:
  145.                     return CheckModulo((QilBinary)n);
  146.                 case QilNodeType.StrLength:
  147.                    
  148.                     return CheckStrLength((QilUnary)n);
  149.                 case QilNodeType.StrConcat:
  150.                     return CheckStrConcat((QilStrConcat)n);
  151.                 case QilNodeType.StrParseQName:
  152.                     return CheckStrParseQName((QilBinary)n);
  153.                 case QilNodeType.Ne:
  154.                    
  155.                     return CheckNe((QilBinary)n);
  156.                 case QilNodeType.Eq:
  157.                     return CheckEq((QilBinary)n);
  158.                 case QilNodeType.Gt:
  159.                     return CheckGt((QilBinary)n);
  160.                 case QilNodeType.Ge:
  161.                     return CheckGe((QilBinary)n);
  162.                 case QilNodeType.Lt:
  163.                     return CheckLt((QilBinary)n);
  164.                 case QilNodeType.Le:
  165.                     return CheckLe((QilBinary)n);
  166.                 case QilNodeType.Is:
  167.                    
  168.                     return CheckIs((QilBinary)n);
  169.                 case QilNodeType.After:
  170.                     return CheckAfter((QilBinary)n);
  171.                 case QilNodeType.Before:
  172.                     return CheckBefore((QilBinary)n);
  173.                 case QilNodeType.Loop:
  174.                    
  175.                     return CheckLoop((QilLoop)n);
  176.                 case QilNodeType.Filter:
  177.                     return CheckFilter((QilLoop)n);
  178.                 case QilNodeType.Sort:
  179.                    
  180.                     return CheckSort((QilLoop)n);
  181.                 case QilNodeType.SortKey:
  182.                     return CheckSortKey((QilSortKey)n);
  183.                 case QilNodeType.DocOrderDistinct:
  184.                     return CheckDocOrderDistinct((QilUnary)n);
  185.                 case QilNodeType.Function:
  186.                    
  187.                     return CheckFunction((QilFunction)n);
  188.                 case QilNodeType.Invoke:
  189.                     return CheckInvoke((QilInvoke)n);
  190.                 case QilNodeType.Content:
  191.                    
  192.                     return CheckContent((QilUnary)n);
  193.                 case QilNodeType.Attribute:
  194.                     return CheckAttribute((QilBinary)n);
  195.                 case QilNodeType.Parent:
  196.                     return CheckParent((QilUnary)n);
  197.                 case QilNodeType.Root:
  198.                     return CheckRoot((QilUnary)n);
  199.                 case QilNodeType.XmlContext:
  200.                     return CheckXmlContext(n);
  201.                 case QilNodeType.Descendant:
  202.                     return CheckDescendant((QilUnary)n);
  203.                 case QilNodeType.DescendantOrSelf:
  204.                     return CheckDescendantOrSelf((QilUnary)n);
  205.                 case QilNodeType.Ancestor:
  206.                     return CheckAncestor((QilUnary)n);
  207.                 case QilNodeType.AncestorOrSelf:
  208.                     return CheckAncestorOrSelf((QilUnary)n);
  209.                 case QilNodeType.Preceding:
  210.                     return CheckPreceding((QilUnary)n);
  211.                 case QilNodeType.FollowingSibling:
  212.                     return CheckFollowingSibling((QilUnary)n);
  213.                 case QilNodeType.PrecedingSibling:
  214.                     return CheckPrecedingSibling((QilUnary)n);
  215.                 case QilNodeType.NodeRange:
  216.                     return CheckNodeRange((QilBinary)n);
  217.                 case QilNodeType.Deref:
  218.                     return CheckDeref((QilBinary)n);
  219.                 case QilNodeType.ElementCtor:
  220.                    
  221.                     return CheckElementCtor((QilBinary)n);
  222.                 case QilNodeType.AttributeCtor:
  223.                     return CheckAttributeCtor((QilBinary)n);
  224.                 case QilNodeType.CommentCtor:
  225.                     return CheckCommentCtor((QilUnary)n);
  226.                 case QilNodeType.PICtor:
  227.                     return CheckPICtor((QilBinary)n);
  228.                 case QilNodeType.TextCtor:
  229.                     return CheckTextCtor((QilUnary)n);
  230.                 case QilNodeType.RawTextCtor:
  231.                     return CheckRawTextCtor((QilUnary)n);
  232.                 case QilNodeType.DocumentCtor:
  233.                     return CheckDocumentCtor((QilUnary)n);
  234.                 case QilNodeType.NamespaceDecl:
  235.                     return CheckNamespaceDecl((QilBinary)n);
  236.                 case QilNodeType.RtfCtor:
  237.                     return CheckRtfCtor((QilBinary)n);
  238.                 case QilNodeType.NameOf:
  239.                    
  240.                     return CheckNameOf((QilUnary)n);
  241.                 case QilNodeType.LocalNameOf:
  242.                     return CheckLocalNameOf((QilUnary)n);
  243.                 case QilNodeType.NamespaceUriOf:
  244.                     return CheckNamespaceUriOf((QilUnary)n);
  245.                 case QilNodeType.PrefixOf:
  246.                     return CheckPrefixOf((QilUnary)n);
  247.                 case QilNodeType.TypeAssert:
  248.                    
  249.                     return CheckTypeAssert((QilTargetType)n);
  250.                 case QilNodeType.IsType:
  251.                     return CheckIsType((QilTargetType)n);
  252.                 case QilNodeType.IsEmpty:
  253.                     return CheckIsEmpty((QilUnary)n);
  254.                 case QilNodeType.XPathNodeValue:
  255.                    
  256.                     return CheckXPathNodeValue((QilUnary)n);
  257.                 case QilNodeType.XPathFollowing:
  258.                     return CheckXPathFollowing((QilUnary)n);
  259.                 case QilNodeType.XPathPreceding:
  260.                     return CheckXPathPreceding((QilUnary)n);
  261.                 case QilNodeType.XPathNamespace:
  262.                     return CheckXPathNamespace((QilUnary)n);
  263.                 case QilNodeType.XsltGenerateId:
  264.                    
  265.                     return CheckXsltGenerateId((QilUnary)n);
  266.                 case QilNodeType.XsltInvokeLateBound:
  267.                     return CheckXsltInvokeLateBound((QilInvokeLateBound)n);
  268.                 case QilNodeType.XsltInvokeEarlyBound:
  269.                     return CheckXsltInvokeEarlyBound((QilInvokeEarlyBound)n);
  270.                 case QilNodeType.XsltCopy:
  271.                     return CheckXsltCopy((QilBinary)n);
  272.                 case QilNodeType.XsltCopyOf:
  273.                     return CheckXsltCopyOf((QilUnary)n);
  274.                 case QilNodeType.XsltConvert:
  275.                     return CheckXsltConvert((QilTargetType)n);
  276.                 default:
  277.                    
  278.                     return CheckUnknown(n);
  279.             }
  280.             #endregion
  281.         }
  282.        
  283.         #region meta
  284.         //-----------------------------------------------
  285.         // meta
  286.         //-----------------------------------------------
  287.         public XmlQueryType CheckQilExpression(QilExpression node)
  288.         {
  289.             Check(node[0].NodeType == QilNodeType.False || node[0].NodeType == QilNodeType.True, node, "IsDebug must either be True or False");
  290.             CheckLiteralValue(node[1], typeof(XmlWriterSettings));
  291.             CheckLiteralValue(node[2], typeof(IList<WhitespaceRule>));
  292.             CheckClassAndNodeType(node[3], typeof(QilList), QilNodeType.GlobalParameterList);
  293.             CheckClassAndNodeType(node[4], typeof(QilList), QilNodeType.GlobalVariableList);
  294.             CheckClassAndNodeType(node[5], typeof(QilList), QilNodeType.FunctionList);
  295.             return XmlQueryTypeFactory.ItemS;
  296.         }
  297.        
  298.         public XmlQueryType CheckFunctionList(QilList node)
  299.         {
  300.             foreach (QilNode child in node)
  301.                 CheckClassAndNodeType(child, typeof(QilFunction), QilNodeType.Function);
  302.             return node.XmlType;
  303.         }
  304.        
  305.         public XmlQueryType CheckGlobalVariableList(QilList node)
  306.         {
  307.             foreach (QilNode child in node)
  308.                 CheckClassAndNodeType(child, typeof(QilIterator), QilNodeType.Let);
  309.             return node.XmlType;
  310.         }
  311.        
  312.         public XmlQueryType CheckGlobalParameterList(QilList node)
  313.         {
  314.             foreach (QilNode child in node)
  315.                 CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter);
  316.             return node.XmlType;
  317.         }
  318.        
  319.         public XmlQueryType CheckActualParameterList(QilList node)
  320.         {
  321.             return node.XmlType;
  322.         }
  323.        
  324.         public XmlQueryType CheckFormalParameterList(QilList node)
  325.         {
  326.             foreach (QilNode child in node)
  327.                 CheckClassAndNodeType(child, typeof(QilParameter), QilNodeType.Parameter);
  328.             return node.XmlType;
  329.         }
  330.        
  331.         public XmlQueryType CheckSortKeyList(QilList node)
  332.         {
  333.             foreach (QilNode child in node)
  334.                 CheckClassAndNodeType(child, typeof(QilSortKey), QilNodeType.SortKey);
  335.             return node.XmlType;
  336.         }
  337.        
  338.         public XmlQueryType CheckBranchList(QilList node)
  339.         {
  340.             return node.XmlType;
  341.         }
  342.        
  343.         public XmlQueryType CheckOptimizeBarrier(QilUnary node)
  344.         {
  345.             return node.Child.XmlType;
  346.         }
  347.        
  348.         public XmlQueryType CheckNoDefaultValue(QilNode node)
  349.         {
  350.             return XmlQueryTypeFactory.None;
  351.         }
  352.        
  353.         public XmlQueryType CheckUnknown(QilNode node)
  354.         {
  355.             return node.XmlType;
  356.         }
  357.        
  358.         #endregion // meta
  359.        
  360.         #region specials
  361.         //-----------------------------------------------
  362.         // specials
  363.         //-----------------------------------------------
  364.         public XmlQueryType CheckDataSource(QilDataSource node)
  365.         {
  366.             CheckXmlType(node.Name, XmlQueryTypeFactory.StringX);
  367.             CheckXmlType(node.BaseUri, XmlQueryTypeFactory.StringX);
  368.             return XmlQueryTypeFactory.NodeNotRtfQ;
  369.         }
  370.        
  371.         public XmlQueryType CheckNop(QilUnary node)
  372.         {
  373.             return node.Child.XmlType;
  374.         }
  375.        
  376.         public XmlQueryType CheckError(QilUnary node)
  377.         {
  378.             CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
  379.             return XmlQueryTypeFactory.None;
  380.         }
  381.        
  382.         public XmlQueryType CheckWarning(QilUnary node)
  383.         {
  384.             CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
  385.             return XmlQueryTypeFactory.Empty;
  386.         }
  387.        
  388.         #endregion // specials
  389.        
  390.         #region variables
  391.         //-----------------------------------------------
  392.         // variables
  393.         //-----------------------------------------------
  394.         public XmlQueryType CheckFor(QilIterator node)
  395.         {
  396.             return node.Binding.XmlType.Prime;
  397.         }
  398.        
  399.         public XmlQueryType CheckLet(QilIterator node)
  400.         {
  401.             return node.Binding.XmlType;
  402.         }
  403.        
  404.         public XmlQueryType CheckParameter(QilParameter node)
  405.         {
  406.             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");
  407.             return node.XmlType;
  408.         }
  409.        
  410.         public XmlQueryType CheckPositionOf(QilUnary node)
  411.         {
  412.             return XmlQueryTypeFactory.IntX;
  413.         }
  414.        
  415.         #endregion // variables
  416.        
  417.         #region literals
  418.         //-----------------------------------------------
  419.         // literals
  420.         //-----------------------------------------------
  421.         public XmlQueryType CheckTrue(QilNode node)
  422.         {
  423.             return XmlQueryTypeFactory.BooleanX;
  424.         }
  425.        
  426.         public XmlQueryType CheckFalse(QilNode node)
  427.         {
  428.             return XmlQueryTypeFactory.BooleanX;
  429.         }
  430.        
  431.         public XmlQueryType CheckLiteralString(QilLiteral node)
  432.         {
  433.             CheckLiteralValue(node, typeof(string));
  434.             return XmlQueryTypeFactory.StringX;
  435.         }
  436.        
  437.         public XmlQueryType CheckLiteralInt32(QilLiteral node)
  438.         {
  439.             CheckLiteralValue(node, typeof(int));
  440.             return XmlQueryTypeFactory.IntX;
  441.         }
  442.        
  443.         public XmlQueryType CheckLiteralInt64(QilLiteral node)
  444.         {
  445.             CheckLiteralValue(node, typeof(long));
  446.             return XmlQueryTypeFactory.IntegerX;
  447.         }
  448.        
  449.         public XmlQueryType CheckLiteralDouble(QilLiteral node)
  450.         {
  451.             CheckLiteralValue(node, typeof(double));
  452.             return XmlQueryTypeFactory.DoubleX;
  453.         }
  454.        
  455.         public XmlQueryType CheckLiteralDecimal(QilLiteral node)
  456.         {
  457.             CheckLiteralValue(node, typeof(decimal));
  458.             return XmlQueryTypeFactory.DecimalX;
  459.         }
  460.        
  461.         public XmlQueryType CheckLiteralQName(QilName node)
  462.         {
  463.             CheckLiteralValue(node, typeof(QilName));
  464.             return XmlQueryTypeFactory.QNameX;
  465.         }
  466.        
  467.         public XmlQueryType CheckLiteralType(QilLiteral node)
  468.         {
  469.             CheckLiteralValue(node, typeof(XmlQueryType));
  470.             return (XmlQueryType)node;
  471.         }
  472.        
  473.         public XmlQueryType CheckLiteralObject(QilLiteral node)
  474.         {
  475.             Check(node.Value != null, node, "Literal value is null");
  476.             return XmlQueryTypeFactory.ItemS;
  477.         }
  478.        
  479.         #endregion // literals
  480.        
  481.         #region boolean operators
  482.         //-----------------------------------------------
  483.         // boolean operators
  484.         //-----------------------------------------------
  485.         public XmlQueryType CheckAnd(QilBinary node)
  486.         {
  487.             CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
  488.             CheckXmlType(node.Right, XmlQueryTypeFactory.BooleanX);
  489.             return XmlQueryTypeFactory.BooleanX;
  490.         }
  491.        
  492.         public XmlQueryType CheckOr(QilBinary node)
  493.         {
  494.             return CheckAnd(node);
  495.         }
  496.        
  497.         public XmlQueryType CheckNot(QilUnary node)
  498.         {
  499.             CheckXmlType(node.Child, XmlQueryTypeFactory.BooleanX);
  500.             return XmlQueryTypeFactory.BooleanX;
  501.         }
  502.        
  503.         #endregion // boolean operators
  504.        
  505.         #region choice
  506.         //-----------------------------------------------
  507.         // choice
  508.         //-----------------------------------------------
  509.         public XmlQueryType CheckConditional(QilTernary node)
  510.         {
  511.             CheckXmlType(node.Left, XmlQueryTypeFactory.BooleanX);
  512.             return XmlQueryTypeFactory.Choice(node.Center.XmlType, node.Right.XmlType);
  513.         }
  514.        
  515.         public XmlQueryType CheckChoice(QilChoice node)
  516.         {
  517.             CheckXmlType(node.Expression, XmlQueryTypeFactory.IntX);
  518.             CheckClassAndNodeType(node.Branches, typeof(QilList), QilNodeType.BranchList);
  519.             Check(node.Branches.Count > 0, node, "Choice must have at least one branch");
  520.             return node.Branches.XmlType;
  521.         }
  522.        
  523.         #endregion // choice
  524.        
  525.         #region collection operators
  526.         //-----------------------------------------------
  527.         // collection operators
  528.         //-----------------------------------------------
  529.         public XmlQueryType CheckLength(QilUnary node)
  530.         {
  531.             return XmlQueryTypeFactory.IntX;
  532.         }
  533.        
  534.         public XmlQueryType CheckSequence(QilList node)
  535.         {
  536.             return node.XmlType;
  537.         }
  538.        
  539.         public XmlQueryType CheckUnion(QilBinary node)
  540.         {
  541.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
  542.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
  543.             return DistinctType(XmlQueryTypeFactory.Sequence(node.Left.XmlType, node.Right.XmlType));
  544.         }
  545.        
  546.         public XmlQueryType CheckIntersection(QilBinary node)
  547.         {
  548.             return CheckUnion(node);
  549.         }
  550.        
  551.         public XmlQueryType CheckDifference(QilBinary node)
  552.         {
  553.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
  554.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
  555.             return XmlQueryTypeFactory.AtMost(node.Left.XmlType, node.Left.XmlType.Cardinality);
  556.         }
  557.        
  558.         public XmlQueryType CheckAverage(QilUnary node)
  559.         {
  560.             XmlQueryType xmlType = node.Child.XmlType;
  561.             CheckNumericXS(node.Child);
  562.             return XmlQueryTypeFactory.PrimeProduct(xmlType, xmlType.MaybeEmpty ? XmlQueryCardinality.ZeroOrOne : XmlQueryCardinality.One);
  563.         }
  564.        
  565.         public XmlQueryType CheckSum(QilUnary node)
  566.         {
  567.             return CheckAverage(node);
  568.         }
  569.        
  570.         public XmlQueryType CheckMinimum(QilUnary node)
  571.         {
  572.             return CheckAverage(node);
  573.         }
  574.        
  575.         public XmlQueryType CheckMaximum(QilUnary node)
  576.         {
  577.             return CheckAverage(node);
  578.         }
  579.        
  580.         #endregion // collection operators
  581.        
  582.         #region arithmetic operators
  583.         //-----------------------------------------------
  584.         // arithmetic operators
  585.         //-----------------------------------------------
  586.         public XmlQueryType CheckNegate(QilUnary node)
  587.         {
  588.             CheckNumericX(node.Child);
  589.             return node.Child.XmlType;
  590.         }
  591.        
  592.         public XmlQueryType CheckAdd(QilBinary node)
  593.         {
  594.             CheckNumericX(node.Left);
  595.             CheckNumericX(node.Right);
  596.             CheckNotDisjoint(node);
  597.             return node.Left.XmlType.TypeCode == XmlTypeCode.None ? node.Right.XmlType : node.Left.XmlType;
  598.         }
  599.        
  600.         public XmlQueryType CheckSubtract(QilBinary node)
  601.         {
  602.             return CheckAdd(node);
  603.         }
  604.        
  605.         public XmlQueryType CheckMultiply(QilBinary node)
  606.         {
  607.             return CheckAdd(node);
  608.         }
  609.        
  610.         public XmlQueryType CheckDivide(QilBinary node)
  611.         {
  612.             return CheckAdd(node);
  613.         }
  614.        
  615.         public XmlQueryType CheckModulo(QilBinary node)
  616.         {
  617.             return CheckAdd(node);
  618.         }
  619.        
  620.         #endregion // arithmetic operators
  621.        
  622.         #region string operators
  623.         //-----------------------------------------------
  624.         // string operators
  625.         //-----------------------------------------------
  626.         public XmlQueryType CheckStrLength(QilUnary node)
  627.         {
  628.             CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
  629.             return XmlQueryTypeFactory.IntX;
  630.         }
  631.        
  632.         public XmlQueryType CheckStrConcat(QilStrConcat node)
  633.         {
  634.             CheckXmlType(node.Delimiter, XmlQueryTypeFactory.StringX);
  635.             CheckXmlType(node.Values, XmlQueryTypeFactory.StringXS);
  636.             return XmlQueryTypeFactory.StringX;
  637.         }
  638.        
  639.         public XmlQueryType CheckStrParseQName(QilBinary node)
  640.         {
  641.             CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
  642.             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");
  643.             return XmlQueryTypeFactory.QNameX;
  644.         }
  645.        
  646.         #endregion // string operators
  647.        
  648.         #region value comparison operators
  649.         //-----------------------------------------------
  650.         // value comparison operators
  651.         //-----------------------------------------------
  652.         public XmlQueryType CheckNe(QilBinary node)
  653.         {
  654.             CheckAtomicX(node.Left);
  655.             CheckAtomicX(node.Right);
  656.             CheckNotDisjoint(node);
  657.             return XmlQueryTypeFactory.BooleanX;
  658.         }
  659.        
  660.         public XmlQueryType CheckEq(QilBinary node)
  661.         {
  662.             return CheckNe(node);
  663.         }
  664.        
  665.         public XmlQueryType CheckGt(QilBinary node)
  666.         {
  667.             return CheckNe(node);
  668.         }
  669.        
  670.         public XmlQueryType CheckGe(QilBinary node)
  671.         {
  672.             return CheckNe(node);
  673.         }
  674.        
  675.         public XmlQueryType CheckLt(QilBinary node)
  676.         {
  677.             return CheckNe(node);
  678.         }
  679.        
  680.         public XmlQueryType CheckLe(QilBinary node)
  681.         {
  682.             return CheckNe(node);
  683.         }
  684.        
  685.         #endregion // value comparison operators
  686.        
  687.         #region node comparison operators
  688.         //-----------------------------------------------
  689.         // node comparison operators
  690.         //-----------------------------------------------
  691.         public XmlQueryType CheckIs(QilBinary node)
  692.         {
  693.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
  694.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf);
  695.             return XmlQueryTypeFactory.BooleanX;
  696.         }
  697.        
  698.         public XmlQueryType CheckAfter(QilBinary node)
  699.         {
  700.             return CheckIs(node);
  701.         }
  702.        
  703.         public XmlQueryType CheckBefore(QilBinary node)
  704.         {
  705.             return CheckIs(node);
  706.         }
  707.        
  708.         #endregion // node comparison operators
  709.        
  710.         #region loops
  711.         //-----------------------------------------------
  712.         // loops
  713.         //-----------------------------------------------
  714.         public XmlQueryType CheckLoop(QilLoop node)
  715.         {
  716.             CheckClass(node[0], typeof(QilIterator));
  717.             Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Loop variable must be a For or Let iterator");
  718.            
  719.             XmlQueryType bodyType = node.Body.XmlType;
  720.             XmlQueryCardinality variableCard = node.Variable.NodeType == QilNodeType.Let ? XmlQueryCardinality.One : node.Variable.Binding.XmlType.Cardinality;
  721.            
  722.             // Loops do not preserve DocOrderDistinct
  723.             if (bodyType.IsDod)
  724.                 return XmlQueryTypeFactory.PrimeProduct(XmlQueryTypeFactory.NodeNotRtfS, variableCard * bodyType.Cardinality);
  725.            
  726.             return XmlQueryTypeFactory.PrimeProduct(bodyType, variableCard * bodyType.Cardinality);
  727.         }
  728.        
  729.         public XmlQueryType CheckFilter(QilLoop node)
  730.         {
  731.             CheckClass(node[0], typeof(QilIterator));
  732.             Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Filter variable must be a For or Let iterator");
  733.             CheckXmlType(node.Body, XmlQueryTypeFactory.BooleanX);
  734.            
  735.             // Attempt to restrict filter's type by checking condition
  736.             XmlQueryType filterType = FindFilterType(node.Variable, node.Body);
  737.             if (filterType != null)
  738.                 return filterType;
  739.            
  740.             return XmlQueryTypeFactory.AtMost(node.Variable.Binding.XmlType, node.Variable.Binding.XmlType.Cardinality);
  741.         }
  742.        
  743.         #endregion // loops
  744.        
  745.         #region sorting
  746.         //-----------------------------------------------
  747.         // sorting
  748.         //-----------------------------------------------
  749.         public XmlQueryType CheckSort(QilLoop node)
  750.         {
  751.             XmlQueryType varType = node.Variable.Binding.XmlType;
  752.            
  753.             CheckClassAndNodeType(node[0], typeof(QilIterator), QilNodeType.For);
  754.             CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.SortKeyList);
  755.            
  756.             // Sort does not preserve DocOrderDistinct
  757.             if (varType.IsDod)
  758.                 return XmlQueryTypeFactory.PrimeProduct(XmlQueryTypeFactory.NodeNotRtfS, varType.Cardinality);
  759.            
  760.             return node.Variable.Binding.XmlType;
  761.         }
  762.        
  763.         public XmlQueryType CheckSortKey(QilSortKey node)
  764.         {
  765.             CheckAtomicX(node.Key);
  766.             CheckXmlType(node.Collation, XmlQueryTypeFactory.StringX);
  767.             return node.Key.XmlType;
  768.         }
  769.        
  770.         public XmlQueryType CheckDocOrderDistinct(QilUnary node)
  771.         {
  772.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
  773.             return DistinctType(node.Child.XmlType);
  774.         }
  775.        
  776.         #endregion // sorting
  777.        
  778.         #region function definition and invocation
  779.         //-----------------------------------------------
  780.         // function definition and invocation
  781.         //-----------------------------------------------
  782.         public XmlQueryType CheckFunction(QilFunction node)
  783.         {
  784.             CheckClassAndNodeType(node[0], typeof(QilList), QilNodeType.FormalParameterList);
  785.             Check(node[2].NodeType == QilNodeType.False || node[2].NodeType == QilNodeType.True, node, "SideEffects must either be True or False");
  786.             Check(node.Definition.XmlType.IsSubtypeOf(node.XmlType), node, "Function definition's xml type must be a subtype of the function's return type");
  787.             return node.XmlType;
  788.         }
  789.        
  790.         public XmlQueryType CheckInvoke(QilInvoke node)
  791.         {
  792.             #if DEBUG
  793.             CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList);
  794.            
  795.             QilList actualArgs = node.Arguments;
  796.             QilList formalArgs = node.Function.Arguments;
  797.             Check(actualArgs.Count == formalArgs.Count, actualArgs, "Invoke argument count must match function's argument count");
  798.            
  799.             for (int i = 0; i < actualArgs.Count; i++)
  800.                 Check(actualArgs[i].XmlType.IsSubtypeOf(formalArgs[i].XmlType), actualArgs[i], "Invoke argument must be a subtype of the invoked function's argument");
  801.             #endif
  802.            
  803.             return node.Function.XmlType;
  804.         }
  805.        
  806.         #endregion // function definition and invocation
  807.        
  808.         #region XML navigation
  809.         //-----------------------------------------------
  810.         // XML navigation
  811.         //-----------------------------------------------
  812.         public XmlQueryType CheckContent(QilUnary node)
  813.         {
  814.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  815.             return XmlQueryTypeFactory.AttributeOrContentS;
  816.         }
  817.        
  818.         public XmlQueryType CheckAttribute(QilBinary node)
  819.         {
  820.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
  821.             CheckXmlType(node.Right, XmlQueryTypeFactory.QNameX);
  822.             return XmlQueryTypeFactory.AttributeQ;
  823.         }
  824.        
  825.         public XmlQueryType CheckParent(QilUnary node)
  826.         {
  827.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  828.             return XmlQueryTypeFactory.DocumentOrElementQ;
  829.         }
  830.        
  831.         public XmlQueryType CheckRoot(QilUnary node)
  832.         {
  833.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  834.             return XmlQueryTypeFactory.NodeNotRtf;
  835.         }
  836.        
  837.         public XmlQueryType CheckXmlContext(QilNode node)
  838.         {
  839.             return XmlQueryTypeFactory.NodeNotRtf;
  840.         }
  841.        
  842.         public XmlQueryType CheckDescendant(QilUnary node)
  843.         {
  844.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  845.             return XmlQueryTypeFactory.ContentS;
  846.         }
  847.        
  848.         public XmlQueryType CheckDescendantOrSelf(QilUnary node)
  849.         {
  850.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  851.             return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.ContentS);
  852.         }
  853.        
  854.         public XmlQueryType CheckAncestor(QilUnary node)
  855.         {
  856.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  857.             return XmlQueryTypeFactory.DocumentOrElementS;
  858.         }
  859.        
  860.         public XmlQueryType CheckAncestorOrSelf(QilUnary node)
  861.         {
  862.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  863.             return XmlQueryTypeFactory.Choice(node.Child.XmlType, XmlQueryTypeFactory.DocumentOrElementS);
  864.         }
  865.        
  866.         public XmlQueryType CheckPreceding(QilUnary node)
  867.         {
  868.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  869.             return XmlQueryTypeFactory.DocumentOrContentS;
  870.         }
  871.        
  872.         public XmlQueryType CheckFollowingSibling(QilUnary node)
  873.         {
  874.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  875.             return XmlQueryTypeFactory.ContentS;
  876.         }
  877.        
  878.         public XmlQueryType CheckPrecedingSibling(QilUnary node)
  879.         {
  880.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  881.             return XmlQueryTypeFactory.ContentS;
  882.         }
  883.        
  884.         public XmlQueryType CheckNodeRange(QilBinary node)
  885.         {
  886.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
  887.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtf);
  888.             return XmlQueryTypeFactory.Choice(node.Left.XmlType, XmlQueryTypeFactory.ContentS, node.Right.XmlType);
  889.         }
  890.        
  891.         public XmlQueryType CheckDeref(QilBinary node)
  892.         {
  893.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
  894.             CheckXmlType(node.Right, XmlQueryTypeFactory.StringX);
  895.             return XmlQueryTypeFactory.ElementS;
  896.         }
  897.        
  898.         #endregion // XML navigation
  899.        
  900.         #region XML construction
  901.         //-----------------------------------------------
  902.         // XML construction
  903.         //-----------------------------------------------
  904.         public XmlQueryType CheckElementCtor(QilBinary node)
  905.         {
  906.             CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX);
  907.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
  908.             return XmlQueryTypeFactory.UntypedElement;
  909.         }
  910.        
  911.         public XmlQueryType CheckAttributeCtor(QilBinary node)
  912.         {
  913.             CheckXmlType(node.Left, XmlQueryTypeFactory.QNameX);
  914.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
  915.             return XmlQueryTypeFactory.UntypedAttribute;
  916.         }
  917.        
  918.         public XmlQueryType CheckCommentCtor(QilUnary node)
  919.         {
  920.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
  921.             return XmlQueryTypeFactory.Comment;
  922.         }
  923.        
  924.         public XmlQueryType CheckPICtor(QilBinary node)
  925.         {
  926.             CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
  927.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeNotRtfS);
  928.             return XmlQueryTypeFactory.PI;
  929.         }
  930.        
  931.         public XmlQueryType CheckTextCtor(QilUnary node)
  932.         {
  933.             CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
  934.             return XmlQueryTypeFactory.Text;
  935.         }
  936.        
  937.         public XmlQueryType CheckRawTextCtor(QilUnary node)
  938.         {
  939.             CheckXmlType(node.Child, XmlQueryTypeFactory.StringX);
  940.             return XmlQueryTypeFactory.Text;
  941.         }
  942.        
  943.         public XmlQueryType CheckDocumentCtor(QilUnary node)
  944.         {
  945.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
  946.             return XmlQueryTypeFactory.UntypedDocument;
  947.         }
  948.        
  949.         public XmlQueryType CheckNamespaceDecl(QilBinary node)
  950.         {
  951.             CheckXmlType(node.Left, XmlQueryTypeFactory.StringX);
  952.             CheckXmlType(node.Right, XmlQueryTypeFactory.StringX);
  953.             return XmlQueryTypeFactory.Namespace;
  954.         }
  955.        
  956.         public XmlQueryType CheckRtfCtor(QilBinary node)
  957.         {
  958.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtfS);
  959.             CheckClassAndNodeType(node.Right, typeof(QilLiteral), QilNodeType.LiteralString);
  960.             return XmlQueryTypeFactory.Node;
  961.         }
  962.        
  963.         #endregion // XML construction
  964.        
  965.         #region Node properties
  966.         //-----------------------------------------------
  967.         // Node properties
  968.         //-----------------------------------------------
  969.         public XmlQueryType CheckNameOf(QilUnary node)
  970.         {
  971.             CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
  972.             return XmlQueryTypeFactory.QNameX;
  973.         }
  974.        
  975.         public XmlQueryType CheckLocalNameOf(QilUnary node)
  976.         {
  977.             CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
  978.             return XmlQueryTypeFactory.StringX;
  979.         }
  980.        
  981.         public XmlQueryType CheckNamespaceUriOf(QilUnary node)
  982.         {
  983.             CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
  984.             return XmlQueryTypeFactory.StringX;
  985.         }
  986.        
  987.         public XmlQueryType CheckPrefixOf(QilUnary node)
  988.         {
  989.             CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
  990.             return XmlQueryTypeFactory.StringX;
  991.         }
  992.        
  993.         #endregion // Node properties
  994.        
  995.         #region Copy operators
  996.         //-----------------------------------------------
  997.         // Copy operators
  998.         //-----------------------------------------------
  999.         public XmlQueryType CheckDeepCopy(QilUnary node)
  1000.         {
  1001.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  1002.             return node.XmlType;
  1003.         }
  1004.        
  1005.         #endregion // Copy operators
  1006.        
  1007.         #region Type operators
  1008.         //-----------------------------------------------
  1009.         // Type operators
  1010.         //-----------------------------------------------
  1011.         public XmlQueryType CheckTypeAssert(QilTargetType node)
  1012.         {
  1013.             CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType);
  1014.             return node.TargetType;
  1015.         }
  1016.        
  1017.         public XmlQueryType CheckIsType(QilTargetType node)
  1018.         {
  1019.             CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType);
  1020.             return XmlQueryTypeFactory.BooleanX;
  1021.         }
  1022.        
  1023.         public XmlQueryType CheckIsEmpty(QilUnary node)
  1024.         {
  1025.             return XmlQueryTypeFactory.BooleanX;
  1026.         }
  1027.        
  1028.         #endregion // Type operators
  1029.        
  1030.         #region XPath operators
  1031.         //-----------------------------------------------
  1032.         // XPath operators
  1033.         //-----------------------------------------------
  1034.         public XmlQueryType CheckXPathNodeValue(QilUnary node)
  1035.         {
  1036.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeS);
  1037.             return XmlQueryTypeFactory.StringX;
  1038.         }
  1039.        
  1040.         public XmlQueryType CheckXPathFollowing(QilUnary node)
  1041.         {
  1042.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  1043.             return XmlQueryTypeFactory.ContentS;
  1044.         }
  1045.        
  1046.         public XmlQueryType CheckXPathPreceding(QilUnary node)
  1047.         {
  1048.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  1049.             return XmlQueryTypeFactory.ContentS;
  1050.         }
  1051.        
  1052.         public XmlQueryType CheckXPathNamespace(QilUnary node)
  1053.         {
  1054.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtf);
  1055.             return XmlQueryTypeFactory.NamespaceS;
  1056.         }
  1057.        
  1058.         #endregion // XPath operators
  1059.        
  1060.         #region XSLT
  1061.         //-----------------------------------------------
  1062.         // XSLT
  1063.         //-----------------------------------------------
  1064.         public XmlQueryType CheckXsltGenerateId(QilUnary node)
  1065.         {
  1066.             CheckXmlType(node.Child, XmlQueryTypeFactory.NodeNotRtfS);
  1067.             return XmlQueryTypeFactory.StringX;
  1068.         }
  1069.        
  1070.         public XmlQueryType CheckXsltInvokeLateBound(QilInvokeLateBound node)
  1071.         {
  1072.             CheckLiteralValue(node[0], typeof(QilName));
  1073.             CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.ActualParameterList);
  1074.             return XmlQueryTypeFactory.ItemS;
  1075.         }
  1076.        
  1077.         public XmlQueryType CheckXsltInvokeEarlyBound(QilInvokeEarlyBound node)
  1078.         {
  1079.             #if DEBUG
  1080.             CheckLiteralValue(node[0], typeof(QilName));
  1081.             CheckLiteralValue(node[1], typeof(MethodInfo));
  1082.             CheckClassAndNodeType(node[2], typeof(QilList), QilNodeType.ActualParameterList);
  1083.            
  1084.             XmlExtensionFunction extFunc = new XmlExtensionFunction(node.Name.LocalName, node.Name.NamespaceUri, node.ClrMethod);
  1085.             QilList actualArgs = node.Arguments;
  1086.             Check(actualArgs.Count == extFunc.Method.GetParameters().Length, actualArgs, "InvokeEarlyBound argument count must match function's argument count");
  1087.            
  1088.             for (int i = 0; i < actualArgs.Count; i++) {
  1089.                 Check(actualArgs[i].XmlType.IsSubtypeOf(extFunc.GetXmlArgumentType(i)), actualArgs[i], "InvokeEarlyBound argument must be a subtype of the invoked function's argument type");
  1090.             }
  1091.             #endif
  1092.            
  1093.             return node.XmlType;
  1094.         }
  1095.        
  1096.         public XmlQueryType CheckXsltCopy(QilBinary node)
  1097.         {
  1098.             CheckXmlType(node.Left, XmlQueryTypeFactory.NodeNotRtf);
  1099.             CheckXmlType(node.Right, XmlQueryTypeFactory.NodeS);
  1100.             return XmlQueryTypeFactory.Choice(node.Left.XmlType, node.Right.XmlType);
  1101.         }
  1102.        
  1103.         public XmlQueryType CheckXsltCopyOf(QilUnary node)
  1104.         {
  1105.             CheckXmlType(node.Child, XmlQueryTypeFactory.Node);
  1106.            
  1107.             if ((node.Child.XmlType.NodeKinds & XmlNodeKindFlags.Document) != 0)
  1108.                 return XmlQueryTypeFactory.NodeNotRtfS;
  1109.            
  1110.             return node.Child.XmlType;
  1111.         }
  1112.        
  1113.         public XmlQueryType CheckXsltConvert(QilTargetType node)
  1114.         {
  1115.             CheckClassAndNodeType(node[1], typeof(QilLiteral), QilNodeType.LiteralType);
  1116.             return node.TargetType;
  1117.         }
  1118.         #endregion // Xslt operators
  1119.        
  1120.        
  1121.         //-----------------------------------------------
  1122.         // Helper functions
  1123.         //-----------------------------------------------
  1124.        
  1125.         [Conditional("DEBUG")]
  1126.         private void Check(bool value, QilNode node, string message)
  1127.         {
  1128.             if (!value)
  1129.                 QilValidationVisitor.SetError(node, message);
  1130.         }
  1131.        
  1132.         [Conditional("DEBUG")]
  1133.         private void CheckLiteralValue(QilNode node, Type clrTypeValue)
  1134.         {
  1135.             Check(node is QilLiteral, node, "Node must be instance of QilLiteral");
  1136.            
  1137.             Type clrType = ((QilLiteral)node).Value.GetType();
  1138.             Check(clrTypeValue.IsAssignableFrom(clrType), node, "Literal value must be of type " + clrTypeValue.Name);
  1139.         }
  1140.        
  1141.         [Conditional("DEBUG")]
  1142.         private void CheckClass(QilNode node, Type clrTypeClass)
  1143.         {
  1144.             Check(clrTypeClass.IsAssignableFrom(node.GetType()), node, "Node must be instance of " + clrTypeClass.Name);
  1145.         }
  1146.        
  1147.         [Conditional("DEBUG")]
  1148.         private void CheckClassAndNodeType(QilNode node, Type clrTypeClass, QilNodeType nodeType)
  1149.         {
  1150.             CheckClass(node, clrTypeClass);
  1151.             Check(node.NodeType == nodeType, node, "Node must have QilNodeType." + nodeType);
  1152.         }
  1153.        
  1154.         [Conditional("DEBUG")]
  1155.         private void CheckXmlType(QilNode node, XmlQueryType xmlType)
  1156.         {
  1157.             Check(node.XmlType.IsSubtypeOf(xmlType), node, "Node's type " + node.XmlType + " is not a subtype of " + xmlType);
  1158.         }
  1159.        
  1160.         [Conditional("DEBUG")]
  1161.         private void CheckNumericX(QilNode node)
  1162.         {
  1163.             Check(node.XmlType.IsNumeric && node.XmlType.IsSingleton && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict singleton numeric type");
  1164.         }
  1165.        
  1166.         [Conditional("DEBUG")]
  1167.         private void CheckNumericXS(QilNode node)
  1168.         {
  1169.             Check(node.XmlType.IsNumeric && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict numeric type");
  1170.         }
  1171.        
  1172.         [Conditional("DEBUG")]
  1173.         private void CheckAtomicX(QilNode node)
  1174.         {
  1175.             Check(node.XmlType.IsAtomicValue && node.XmlType.IsStrict, node, "Node's type " + node.XmlType + " must be a strict atomic value type");
  1176.         }
  1177.        
  1178.         [Conditional("DEBUG")]
  1179.         private void CheckNotDisjoint(QilBinary node)
  1180.         {
  1181.             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);
  1182.         }
  1183.        
  1184.         private XmlQueryType DistinctType(XmlQueryType type)
  1185.         {
  1186.             if (type.Cardinality == XmlQueryCardinality.More)
  1187.                 return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.OneOrMore);
  1188.            
  1189.             if (type.Cardinality == XmlQueryCardinality.NotOne)
  1190.                 return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.ZeroOrMore);
  1191.            
  1192.             return type;
  1193.         }
  1194.        
  1195.         private XmlQueryType FindFilterType(QilIterator variable, QilNode body)
  1196.         {
  1197.             XmlQueryType leftType;
  1198.             QilBinary binary;
  1199.            
  1200.             if (body.XmlType.TypeCode == XmlTypeCode.None)
  1201.                 return XmlQueryTypeFactory.None;
  1202.            
  1203.             switch (body.NodeType) {
  1204.                 case QilNodeType.False:
  1205.                     return XmlQueryTypeFactory.Empty;
  1206.                 case QilNodeType.IsType:
  1207.                    
  1208.                     // If testing the type of "variable", then filter type can be restricted
  1209.                     if (Ref.Equals(((QilTargetType)body).Source, variable))
  1210.                         return XmlQueryTypeFactory.AtMost(((QilTargetType)body).TargetType, variable.Binding.XmlType.Cardinality);
  1211.                     break;
  1212.                 case QilNodeType.And:
  1213.                    
  1214.                     // Both And conditions can be used to restrict filter's type
  1215.                     leftType = FindFilterType(variable, ((QilBinary)body).Left);
  1216.                     if (leftType != null)
  1217.                         return leftType;
  1218.                    
  1219.                     return FindFilterType(variable, ((QilBinary)body).Right);
  1220.                 case QilNodeType.Eq:
  1221.                    
  1222.                     // Restrict cardinality if position($iterator) = $pos is found
  1223.                     binary = (QilBinary)body;
  1224.                     if (binary.Left.NodeType == QilNodeType.PositionOf) {
  1225.                         if (Ref.Equals(((QilUnary)binary.Left).Child, variable))
  1226.                             return XmlQueryTypeFactory.AtMost(variable.Binding.XmlType, XmlQueryCardinality.ZeroOrOne);
  1227.                     }
  1228.                     break;
  1229.             }
  1230.            
  1231.             return null;
  1232.         }
  1233.     }
  1234. }

Developer Fusion