Пример #1
0
        public QilNode Function(string prefix, string name, IList <QilNode> args)
        {
            Debug.Assert(prefix.Length == 0);
            QilIterator i = _f.For(_fixupNode);
            QilNode     matches;

            if (name == "id")
            {
                Debug.Assert(
                    args.Count == 1 && args[0].NodeType == QilNodeType.LiteralString,
                    "Function id() must have one literal string argument"
                    );
                matches = _f.Id(i, args[0]);
            }
            else
            {
                Debug.Assert(name == "key", "Unexpected function");
                Debug.Assert(
                    args.Count == 2 &&
                    args[0].NodeType == QilNodeType.LiteralString && args[1].NodeType == QilNodeType.LiteralString,
                    "Function key() must have two literal string arguments"
                    );
                matches = _environment.ResolveFunction(prefix, name, args, new XsltFunctionFocus(i));
            }

            QilIterator j;
            QilLoop     result = _f.BaseFactory.Filter(i, _f.Not(_f.IsEmpty(_f.Filter(j = _f.For(matches), _f.Is(j, i)))));

            SetPriority(result, 0.5);
            SetLastParent(result, result);
            return(result);
        }
Пример #2
0
        // a/b/c -> self::c[parent::b[parent::a]]
        // a/b//c -> self::c[ancestor::b[parent::a]]
        // a/b -> self::b[parent::a]
        //  -> JoinStep(Axis('a'), Axis('b'))
        //   -> Filter('b' & Parent(Filter('a')))
        // a//b
        //  -> JoinStep(Axis('a'), JoingStep(Axis(DescendantOrSelf), Axis('b')))
        //   -> JoinStep(Filter('a'), JoingStep(Nop(null), Filter('b')))
        //    -> JoinStep(Filter('a'), Nop(Filter('b')))
        //     -> Filter('b' & Ancestor(Filter('a')))
        public QilNode JoinStep(QilNode left, QilNode right)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);
            if (left.NodeType == QilNodeType.Nop)
            {
                QilUnary nop = (QilUnary)left;
                Debug.Assert(nop.Child == _fixupNode);
                nop.Child = right;  // We use Nop as a flag that DescendantOrSelf axis was used between steps.
                return(nop);
            }
            Debug.Assert(GetLastParent(left) == left, "Left is always single axis and never the step");
            Debug.Assert(left.NodeType == QilNodeType.Filter);
            CleanAnnotation(left);
            QilLoop parentFilter = (QilLoop)left;
            bool    ancestor     = false;

            {
                if (right.NodeType == QilNodeType.Nop)
                {
                    ancestor = true;
                    QilUnary nop = (QilUnary)right;
                    Debug.Assert(nop.Child != null);
                    right = nop.Child;
                }
            }
            Debug.Assert(right.NodeType == QilNodeType.Filter);
            QilLoop lastParent = GetLastParent(right);

            FixupFilterBinding(parentFilter, ancestor ? _f.Ancestor(lastParent.Variable) : _f.Parent(lastParent.Variable));
            lastParent.Body = _f.And(lastParent.Body, _f.Not(_f.IsEmpty(parentFilter)));
            SetPriority(right, 0.5);
            SetLastParent(right, parentFilter);
            return(right);
        }
Пример #3
0
        /// <summary>
        /// Recursively analyze the definition of a function.
        /// </summary>
        private static void AnalyzeDefinition(QilNode nd)
        {
            Debug.Assert(XmlILConstructInfo.Read(nd).PushToWriterLast,
                         "Only need to analyze expressions which will be compiled in push mode.");

            switch (nd.NodeType)
            {
            case QilNodeType.Invoke:
                // Invoke node can either be compiled as IteratorThenWriter, or Writer.
                // Since IteratorThenWriter involves caching the results of the function call
                // and iterating over them, .tailcall cannot be used
                if (XmlILConstructInfo.Read(nd).ConstructMethod == XmlILConstructMethod.Writer)
                {
                    OptimizerPatterns.Write(nd).AddPattern(OptimizerPatternName.TailCall);
                }
                break;

            case QilNodeType.Loop: {
                // Recursively analyze Loop return value
                QilLoop ndLoop = (QilLoop)nd;
                if (ndLoop.Variable.NodeType == QilNodeType.Let || !ndLoop.Variable.Binding.XmlType.MaybeMany)
                {
                    AnalyzeDefinition(ndLoop.Body);
                }
                break;
            }

            case QilNodeType.Sequence: {
                // Recursively analyze last expression in Sequence
                QilList ndSeq = (QilList)nd;
                if (ndSeq.Count > 0)
                {
                    AnalyzeDefinition(ndSeq[ndSeq.Count - 1]);
                }
                break;
            }

            case QilNodeType.Choice: {
                // Recursively analyze Choice branches
                QilChoice ndChoice = (QilChoice)nd;
                for (int i = 0; i < ndChoice.Branches.Count; i++)
                {
                    AnalyzeDefinition(ndChoice.Branches[i]);
                }
                break;
            }

            case QilNodeType.Conditional: {
                // Recursively analyze Conditional branches
                QilTernary ndCond = (QilTernary)nd;
                AnalyzeDefinition(ndCond.Center);
                AnalyzeDefinition(ndCond.Right);
                break;
            }

            case QilNodeType.Nop:
                AnalyzeDefinition(((QilUnary)nd).Child);
                break;
            }
        }
Пример #4
0
 public void AssertFilter(QilLoop filter)
 {
     Debug.Assert(filter.NodeType == QilNodeType.Filter, "XPathPatternBuilder expected to generate list of Filters on top level");
     Debug.Assert(filter.Variable.XmlType.IsSubtypeOf(T.NodeNotRtf));
     Debug.Assert(filter.Variable.Binding.NodeType == QilNodeType.Unknown);  // fixupNode
     Debug.Assert(filter.Body.XmlType.IsSubtypeOf(T.Boolean));
 }
Пример #5
0
        private static void SetLastParent(QilNode node, QilLoop parent)
        {
            Debug.Assert(parent.NodeType == QilNodeType.Filter);
            Annotation ann = (Annotation)node.Annotation ?? new Annotation();

            ann.Parent      = parent;
            node.Annotation = ann;
        }
            public QilNode GetLast()
            {
                QilLoop     clone = (QilLoop)cloner.Clone(baseContext);
                QilIterator i     = f.For(f.Parent(GetCurrent()));

                clone.Variable.Binding = f.Content(i);
                return(f.XsltConvert(f.Length(f.Loop(i, clone)), T.DoubleX));
            }
Пример #7
0
        // -------------------------------------- GetPredicateBuilder() ---------------------------------------

        public IXPathBuilder <QilNode> GetPredicateBuilder(QilNode ctx)
        {
            QilLoop context = (QilLoop)ctx;

            Debug.Assert(context != null, "Predicate always has step so it can't have context == null");
            Debug.Assert(context.Variable.NodeType == QilNodeType.For, "It shouldn't be Let, becaus predicates in PatternBuilder don't produce cached tuples.");
            return(_predicateBuilder);
        }
Пример #8
0
        /// <summary>
        /// Analyze loop.
        /// </summary>
        protected override void AnalyzeLoop(QilLoop ndLoop, XmlILConstructInfo info)
        {
            // Constructing attributes/namespaces in a loop can cause duplicates, namespaces after attributes, etc.
            if (ndLoop.XmlType.MaybeMany)
            {
                CheckAttributeNamespaceConstruct(ndLoop.XmlType);
            }

            base.AnalyzeLoop(ndLoop, info);
        }
Пример #9
0
        public void AddTemplateMatch(Template template, QilLoop filter)
        {
            List <TemplateMatch> matchesForMode;

            if (!TemplateMatches.TryGetValue(template.Mode, out matchesForMode))
            {
                matchesForMode = TemplateMatches[template.Mode] = new List <TemplateMatch>();
            }
            matchesForMode.Add(new TemplateMatch(template, filter));
        }
Пример #10
0
        //The structure of result is a Filter, variable is current node, body is the match condition.
        //Previous predicate build logic in XPathPatternBuilder is match from right to left, which have 2^n complexiy when have lots of position predicates. TFS #368771
        //Now change the logic to: If predicates contains position/last predicates, given the current node, filter out all the nodes that match the predicates,
        //and then check if current node is in the result set.
        public QilNode BuildPredicates(QilNode nodeset, List <QilNode> predicates)
        {
            //convert predicates to boolean type
            List <QilNode> convertedPredicates = new List <QilNode>(predicates.Count);

            foreach (var predicate in predicates)
            {
                convertedPredicates.Add(XPathBuilder.PredicateToBoolean(predicate, _f, _predicateEnvironment));
            }

            QilLoop     nodeFilter = (QilLoop)nodeset;
            QilIterator current    = nodeFilter.Variable;

            //If no last() and position() in predicates, use nodeFilter.Variable to fixup current
            //because all the predicates only based on the input variable, no matter what other predicates are.
            if (_predicateEnvironment.numFixupLast == 0 && _predicateEnvironment.numFixupPosition == 0)
            {
                foreach (var predicate in convertedPredicates)
                {
                    nodeFilter.Body = _f.And(nodeFilter.Body, predicate);
                }
                nodeFilter.Body = _predicateEnvironment.fixupVisitor.Fixup(nodeFilter.Body, current, null);
            }
            //If any preidcate contains last() or position() node, then the current node is based on previous predicates,
            //for instance, a[...][2] is match second node after filter 'a[...]' instead of second 'a'.
            else
            {
                //filter out the siblings
                QilIterator parentIter = _f.For(_f.Parent(current));
                QilNode     sibling    = _f.Content(parentIter);
                //generate filter based on input filter
                QilLoop siblingFilter = (QilLoop)nodeset.DeepClone(_f.BaseFactory);
                siblingFilter.Variable.Binding = sibling;
                siblingFilter = (QilLoop)_f.Loop(parentIter, siblingFilter);

                //build predicates from left to right to get all the matching nodes
                QilNode matchingSet = siblingFilter;
                foreach (var predicate in convertedPredicates)
                {
                    matchingSet = XPathBuilder.BuildOnePredicate(matchingSet, predicate, /*isReverseStep*/ false,
                                                                 _f, _predicateEnvironment.fixupVisitor,
                                                                 ref _predicateEnvironment.numFixupCurrent, ref _predicateEnvironment.numFixupPosition, ref _predicateEnvironment.numFixupLast);
                }

                //check if the matching nodes contains the current node
                QilIterator matchNodeIter = _f.For(matchingSet);
                QilNode     filterCurrent = _f.Filter(matchNodeIter, _f.Is(matchNodeIter, current));
                nodeFilter.Body = _f.Not(_f.IsEmpty(filterCurrent));
                //for passing type check, explicit say the result is target type
                nodeFilter.Body = _f.And(_f.IsType(current, nodeFilter.XmlType), nodeFilter.Body);
            }

            SetPriority(nodeset, 0.5);
            return(nodeset);
        }
Пример #11
0
        QilNode BuildAxisFilter(QilNode qilAxis, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri)
        {
            XmlNodeKindFlags original = qilAxis.XmlType.NodeKinds;
            XmlNodeKindFlags required = AxisTypeMask(original, nodeType, xpathAxis);

            QilIterator itr;

            if (required == 0)
            {
                return(f.Sequence());
            }
            else if (required == original)
            {
            }
            else
            {
                qilAxis         = f.Filter(itr = f.For(qilAxis), f.IsType(itr, T.NodeChoice(required)));
                qilAxis.XmlType = T.PrimeProduct(T.NodeChoice(required), qilAxis.XmlType.Cardinality);


                // Without code bellow IlGeneragion gives stack overflow exception for the following passage.
                //<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
                //    <xsl:template match="/">
                //        <xsl:value-of select="descendant::author/@id | comment()" />
                //    </xsl:template>
                //</xsl:stylesheet>

                // ToDo: remove this code when IlGen bug will be fixed.
                if (qilAxis.NodeType == QilNodeType.Filter)
                {
                    QilLoop filter = (QilLoop)qilAxis;
                    filter.Body = f.And(filter.Body,
                                        name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri))    :  // ns:bar || bar
                                        nsUri != null                  ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:*
                                        name != null                  ? f.Eq(f.LocalNameOf(itr), f.String(name))     :  // *:foo
                                        /*name  == nsUri == null*/ f.True()                                             // *
                                        );
                    return(filter);
                }
            }

            return(f.Filter(itr = f.For(qilAxis),
                            name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri))    :  // ns:bar || bar
                            nsUri != null                  ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:*
                            name != null                  ? f.Eq(f.LocalNameOf(itr), f.String(name))     :  // *:foo
                            /*name  == nsUri == null*/ f.True()                                             // *
                            ));
        }
Пример #12
0
        public TemplateMatch(Template template, QilLoop filter)
        {
            _template  = template;
            _priority  = double.IsNaN(template.Priority) ? XPathPatternBuilder.GetPriority(filter) : template.Priority;
            _iterator  = filter.Variable;
            _condition = filter.Body;

            XPathPatternBuilder.CleanAnnotation(filter);
            NipOffTypeNameCheck();

            Debug.Assert(
                _qname == null ||
                _nodeKind == XmlNodeKindFlags.Element || _nodeKind == XmlNodeKindFlags.Attribute || _nodeKind == XmlNodeKindFlags.PI,
                "qname may be not null only for element, attribute, or PI patterns"
                );
        }
        public QilNode Predicate(QilNode node, QilNode condition, bool isReverseStep)
        {
            Debug.Assert(isReverseStep == false, "patterns can't have reverse axe");
            QilLoop nodeFilter = (QilLoop)node;

            if (condition.XmlType.TypeCode == XmlTypeCode.Double)
            {
                predicateEnvironment.SetContext(nodeFilter);
                condition = f.Eq(condition, predicateEnvironment.GetPosition());
            }
            else
            {
                condition = f.ConvertToBoolean(condition);
            }

            nodeFilter.Body = f.And(nodeFilter.Body, condition);
            SetPriority(node, 0.5);
            return(node);
        }
Пример #14
0
        /// <summary>
        /// Analyze loop.
        /// </summary>
        protected virtual void AnalyzeLoop(QilLoop ndLoop, XmlILConstructInfo info)
        {
            XmlQueryType typ = ndLoop.XmlType;

            // Ensure that construct method is Writer
            info.ConstructMethod = XmlILConstructMethod.Writer;

            if (!typ.IsSingleton)
            {
                StartLoop(typ, info);
            }

            // Body constructs content
            ndLoop.Body = AnalyzeContent(ndLoop.Body);

            if (!typ.IsSingleton)
            {
                EndLoop(typ, info);
            }
        }
            public QilNode GetPosition()
            {
                QilLoop          clone     = (QilLoop)cloner.Clone(baseContext);
                XmlNodeKindFlags nodeKinds = baseContext.XmlType.NodeKinds;

                // baseContext either always returns attributes (attribute::), or never returns attributes or namespaces (child::)
                if (nodeKinds == XmlNodeKindFlags.Attribute)
                {
                    QilIterator i = f.For(f.Parent(GetCurrent()));
                    clone.Variable.Binding = f.Content(i);
                    clone.Body             = f.And(clone.Body, f.Before(clone.Variable, GetCurrent()));
                    clone = f.BaseFactory.Loop(i, clone);
                }
                else
                {
                    Debug.Assert((nodeKinds & (XmlNodeKindFlags.Attribute | XmlNodeKindFlags.Namespace)) == XmlNodeKindFlags.None);
                    clone.Variable.Binding = f.PrecedingSibling(GetCurrent());
                }
                return(f.Add(f.Double(1), f.XsltConvert(f.Length(clone), T.DoubleX)));
            }
Пример #16
0
 // Filers that travers Content being converted to global travers:
 // Filter($j= ... Filter($i = Content(fixup), ...))  -> Filter($j= ... Filter($i = Loop($j = DesendentOrSelf(Root(fixup)), Content($j), ...)))
 protected override QilNode VisitLoop(QilLoop n)
 {
     if (n.Variable.Binding.NodeType == QilNodeType.Root || n.Variable.Binding.NodeType == QilNodeType.Deref)
     {
         // This is absolute path already. We shouldn't touch it
         return(n);
     }
     if (n.Variable.Binding.NodeType == QilNodeType.Content)
     {
         // This is "begin" of reletive path. Let's rewrite it as absolute:
         QilUnary content = (QilUnary)n.Variable.Binding;
         Debug.Assert(content.Child == this.fixup, "Unexpected content node");
         QilIterator it = f.For(f.DescendantOrSelf(f.Root(this.fixup)));
         content.Child      = it;
         n.Variable.Binding = f.Loop(it, content);
         return(n);
     }
     n.Variable.Binding = Visit(n.Variable.Binding);
     return(n);
 }
        QilNode BuildAxisFilter(QilNode qilAxis, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri)
        {
            XmlNodeKindFlags original = qilAxis.XmlType.NodeKinds;
            XmlNodeKindFlags required = AxisTypeMask(original, nodeType, xpathAxis);

            QilIterator itr;

            if (required == 0)
            {
                return(f.Sequence());
            }
            else if (required == original)
            {
            }
            else
            {
                qilAxis         = f.Filter(itr = f.For(qilAxis), f.IsType(itr, T.NodeChoice(required)));
                qilAxis.XmlType = T.PrimeProduct(T.NodeChoice(required), qilAxis.XmlType.Cardinality);



                if (qilAxis.NodeType == QilNodeType.Filter)
                {
                    QilLoop filter = (QilLoop)qilAxis;
                    filter.Body = f.And(filter.Body,
                                        name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri))    :  // ns:bar || bar
                                        nsUri != null                  ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:*
                                        name != null                  ? f.Eq(f.LocalNameOf(itr), f.String(name))     :  // *:foo
                                        /*name  == nsUri == null*/ f.True()                                             // *
                                        );
                    return(filter);
                }
            }

            return(f.Filter(itr = f.For(qilAxis),
                            name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri))    :  // ns:bar || bar
                            nsUri != null                  ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:*
                            name != null                  ? f.Eq(f.LocalNameOf(itr), f.String(name))     :  // *:foo
                            /*name  == nsUri == null*/ f.True()                                             // *
                            ));
        }
Пример #18
0
        private static QilLoop BuildAxisFilter(QilPatternFactory f, QilIterator itr, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri)
        {
            QilNode nameTest = (
                name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) :                   // ns:bar || bar
                nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) :                                // ns:*
                name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) :                                     // *:foo
                                                                          /*name  == nsUri == null*/ f.True() // *
                );

            XmlNodeKindFlags intersection = XPathBuilder.AxisTypeMask(itr.XmlType.NodeKinds, nodeType, xpathAxis);

            QilNode typeTest = (
                intersection == 0 ? f.False() :                    // input & required doesn't intersect
                intersection == itr.XmlType.NodeKinds ? f.True() : // input is subset of required
                                                                    /*else*/ f.IsType(itr, T.NodeChoice(intersection))
                );

            QilLoop filter = f.BaseFactory.Filter(itr, f.And(typeTest, nameTest));

            filter.XmlType = T.PrimeProduct(T.NodeChoice(intersection), filter.XmlType.Cardinality);

            return(filter);
        }
Пример #19
0
 protected override QilNode VisitFilter(QilLoop n)
 {
     return(VisitLoop(n));
 }
Пример #20
0
 private void FixupFilterBinding(QilLoop filter, QilNode newBinding)
 {
     AssertFilter(filter);
     filter.Variable.Binding = newBinding;
 }
 public void SetContext(QilLoop filter)
 {
     this.baseContext = filter;
 }