protected virtual void AnalyzeCopy(QilNode ndCopy, XmlILConstructInfo info)
        {
            XmlQueryType typ = ndCopy.XmlType !;

            // Copying item(s) to output involves looping if there is not exactly one item in the sequence
            if (!typ.IsSingleton)
            {
                StartLoop(typ, info);
            }

            // Determine state transitions that may take place
            if (MaybeContent(typ))
            {
                if (MaybeAttrNmsp(typ))
                {
                    // Node might be Attr/Nmsp or non-Attr/Nmsp, so transition from EnumAttrs to WithinContent *may* occur
                    if (this.xstates == PossibleXmlStates.EnumAttrs)
                    {
                        this.xstates = PossibleXmlStates.Any;
                    }
                }
                else
                {
                    // Node is guaranteed not to be Attr/Nmsp, so transition to WithinContent will occur if starting
                    // state is EnumAttrs or if constructing within an element (guaranteed to be in EnumAttrs or WithinContent state)
                    if (this.xstates == PossibleXmlStates.EnumAttrs || this.withinElem)
                    {
                        this.xstates = PossibleXmlStates.WithinContent;
                    }
                }
            }

            if (!typ.IsSingleton)
            {
                EndLoop(typ, info);
            }
        }
Example #2
0
        /// <summary>
        /// Perform analysis on the specified constructor and its content.  Return the ndContent that was passed in,
        /// or a replacement.
        /// </summary>
        public virtual QilNode Analyze(QilNode ndConstr, QilNode ndContent)
        {
            if (ndConstr == null)
            {
                // Root expression is analyzed
                this.parentInfo = null;
                this.xstates    = PossibleXmlStates.WithinSequence;
                this.withinElem = false;

                Debug.Assert(ndContent != null);
                ndContent = AnalyzeContent(ndContent);
            }
            else
            {
                this.parentInfo = XmlILConstructInfo.Write(ndConstr);

                if (ndConstr.NodeType == QilNodeType.Function)
                {
                    // Results of function should be pushed to writer
                    this.parentInfo.ConstructMethod = XmlILConstructMethod.Writer;

                    // Start with PossibleXmlStates.None and then add additional possible starting states
                    PossibleXmlStates xstates = PossibleXmlStates.None;
                    foreach (XmlILConstructInfo infoCaller in this.parentInfo.CallersInfo)
                    {
                        if (xstates == PossibleXmlStates.None)
                        {
                            xstates = infoCaller.InitialStates;
                        }
                        else if (xstates != infoCaller.InitialStates)
                        {
                            xstates = PossibleXmlStates.Any;
                        }

                        // Function's results are pushed to Writer, so make sure that Invoke nodes' construct methods match
                        infoCaller.PushToWriterFirst = true;
                    }
                    this.parentInfo.InitialStates = xstates;
                }
                else
                {
                    // Build a standalone tree, with this constructor as its root
                    if (ndConstr.NodeType != QilNodeType.Choice)
                    {
                        this.parentInfo.InitialStates = this.parentInfo.FinalStates = PossibleXmlStates.WithinSequence;
                    }

                    // Don't stream Rtf; fully cache the Rtf and copy it into any containing tree in order to simplify XmlILVisitor.VisitRtfCtor
                    if (ndConstr.NodeType != QilNodeType.RtfCtor)
                    {
                        this.parentInfo.ConstructMethod = XmlILConstructMethod.WriterThenIterator;
                    }
                }

                // Set withinElem = true if analyzing element content
                this.withinElem = (ndConstr.NodeType == QilNodeType.ElementCtor);

                switch (ndConstr.NodeType)
                {
                case QilNodeType.DocumentCtor: this.xstates = PossibleXmlStates.WithinContent; break;

                case QilNodeType.ElementCtor: this.xstates = PossibleXmlStates.EnumAttrs; break;

                case QilNodeType.AttributeCtor: this.xstates = PossibleXmlStates.WithinAttr; break;

                case QilNodeType.NamespaceDecl: Debug.Assert(ndContent == null); break;

                case QilNodeType.TextCtor: Debug.Assert(ndContent == null); break;

                case QilNodeType.RawTextCtor: Debug.Assert(ndContent == null); break;

                case QilNodeType.CommentCtor: this.xstates = PossibleXmlStates.WithinComment; break;

                case QilNodeType.PICtor: this.xstates = PossibleXmlStates.WithinPI; break;

                case QilNodeType.XsltCopy: this.xstates = PossibleXmlStates.Any; break;

                case QilNodeType.XsltCopyOf: Debug.Assert(ndContent == null); break;

                case QilNodeType.Function: this.xstates = this.parentInfo.InitialStates; break;

                case QilNodeType.RtfCtor: this.xstates = PossibleXmlStates.WithinContent; break;

                case QilNodeType.Choice: this.xstates = PossibleXmlStates.Any; break;

                default: Debug.Assert(false, ndConstr.NodeType + " is not handled by XmlILStateAnalyzer."); break;
                }

                if (ndContent != null)
                {
                    ndContent = AnalyzeContent(ndContent);
                }

                if (ndConstr.NodeType == QilNodeType.Choice)
                {
                    AnalyzeChoice(ndConstr as QilChoice, this.parentInfo);
                }

                // Since Function will never be another node's content, set its final states here
                if (ndConstr.NodeType == QilNodeType.Function)
                {
                    this.parentInfo.FinalStates = this.xstates;
                }
            }

            return(ndContent);
        }
        /// <summary>
        /// Calculate starting xml states that will result when iterating over and constructing an expression of the specified type.
        /// </summary>
        private void StartLoop(XmlQueryType typ, XmlILConstructInfo info) {
            Debug.Assert(!typ.IsSingleton);

            // This is tricky, because the looping introduces a feedback loop:
            //   1. Because loops may be executed many times, the beginning set of states must include the ending set of states.
            //   2. Because loops may be executed 0 times, the final set of states after all looping is complete must include
            //      the initial set of states.
            //
            // +-- states-initial
            // |         |
            // | states-begin-loop <--+
            // |         |            |
            // |  +--------------+    |
            // |  | Construction |    |
            // |  +--------------+    |
            // |         |            |
            // |  states-end-loop ----+
            // |         |
            // +--> states-final

            // Save starting loop states
            info.BeginLoopStates = this.xstates;

            if (typ.MaybeMany) {
                // If transition might occur from EnumAttrs to WithinContent, then states-end might be WithinContent, which
                // means states-begin needs to also include WithinContent.
                if (this.xstates == PossibleXmlStates.EnumAttrs && MaybeContent(typ))
                    info.BeginLoopStates = this.xstates = PossibleXmlStates.Any;
            }
        }
        /// <summary>
        /// Calculate ending xml states that will result when iterating over and constructing an expression of the specified type.
        /// </summary>
        private void EndLoop(XmlQueryType typ, XmlILConstructInfo info) {
            Debug.Assert(!typ.IsSingleton);

            // Save ending loop states
            info.EndLoopStates = this.xstates;

            // If it's possible to loop zero times, then states-final needs to include states-initial
            if (typ.MaybeEmpty && info.InitialStates != this.xstates)
                this.xstates = PossibleXmlStates.Any;
        }
        /// <summary>
        /// Analyze copying items.
        /// </summary>
        protected virtual void AnalyzeCopy(QilNode ndCopy, XmlILConstructInfo info) {
            XmlQueryType typ = ndCopy.XmlType;

            // Copying item(s) to output involves looping if there is not exactly one item in the sequence
            if (!typ.IsSingleton)
                StartLoop(typ, info);

            // Determine state transitions that may take place
            if (MaybeContent(typ)) {
                if (MaybeAttrNmsp(typ)) {
                    // Node might be Attr/Nmsp or non-Attr/Nmsp, so transition from EnumAttrs to WithinContent *may* occur
                    if (this.xstates == PossibleXmlStates.EnumAttrs)
                        this.xstates = PossibleXmlStates.Any;
                }
                else {
                    // Node is guaranteed not to be Attr/Nmsp, so transition to WithinContent will occur if starting
                    // state is EnumAttrs or if constructing within an element (guaranteed to be in EnumAttrs or WithinContent state)
                    if (this.xstates == PossibleXmlStates.EnumAttrs || this.withinElem)
                        this.xstates = PossibleXmlStates.WithinContent;
                }
            }

            if (!typ.IsSingleton)
                EndLoop(typ, info);
        }
        /// <summary>
        /// Analyze choice.
        /// </summary>
        protected virtual void AnalyzeChoice(QilChoice ndChoice, XmlILConstructInfo info) {
            PossibleXmlStates xstatesChoice;
            int idx;

            // Visit default branch; save resulting states
            idx = ndChoice.Branches.Count - 1;
            ndChoice.Branches[idx] = AnalyzeContent(ndChoice.Branches[idx]);
            xstatesChoice = this.xstates;

            // Visit all other branches
            while (--idx >= 0) {
                // Restore starting states and visit the next branch
                this.xstates = info.InitialStates;
                ndChoice.Branches[idx] = AnalyzeContent(ndChoice.Branches[idx]);

                // Choice ending states consist of combination of all branch states
                if (xstatesChoice != this.xstates)
                    xstatesChoice = PossibleXmlStates.Any;
            }

            this.xstates = xstatesChoice;
        }
        /// <summary>
        /// Analyze conditional.
        /// </summary>
        protected virtual void AnalyzeConditional(QilTernary ndCond, XmlILConstructInfo info) {
            PossibleXmlStates xstatesTrue;

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

            // Visit true branch; save resulting states
            ndCond.Center = AnalyzeContent(ndCond.Center);
            xstatesTrue = this.xstates;

            // Restore starting states and visit false branch
            this.xstates = info.InitialStates;
            ndCond.Right = AnalyzeContent(ndCond.Right);

            // Conditional ending states consist of combination of true and false branch states
            if (xstatesTrue != this.xstates)
                this.xstates = PossibleXmlStates.Any;
        }
        /// <summary>
        /// Perform analysis on the specified constructor and its content.  Return the ndContent that was passed in,
        /// or a replacement.
        /// </summary>
        public virtual QilNode Analyze(QilNode ndConstr, QilNode ndContent) {
            if (ndConstr == null) {
                // Root expression is analyzed
                this.parentInfo = null;
                this.xstates = PossibleXmlStates.WithinSequence;
                this.withinElem = false;

                Debug.Assert(ndContent != null);
                ndContent = AnalyzeContent(ndContent);
            }
            else {
                this.parentInfo = XmlILConstructInfo.Write(ndConstr);

                if (ndConstr.NodeType == QilNodeType.Function) {
                    // Results of function should be pushed to writer
                    this.parentInfo.ConstructMethod = XmlILConstructMethod.Writer;

                    // Start with PossibleXmlStates.None and then add additional possible starting states
                    PossibleXmlStates xstates = PossibleXmlStates.None;
                    foreach (XmlILConstructInfo infoCaller in this.parentInfo.CallersInfo) {
                        if (xstates == PossibleXmlStates.None) {
                            xstates = infoCaller.InitialStates;
                        } 
                        else if (xstates != infoCaller.InitialStates) {
                            xstates = PossibleXmlStates.Any;
                        }

                        // Function's results are pushed to Writer, so make sure that Invoke nodes' construct methods match
                        infoCaller.PushToWriterFirst = true;
                    }
                    this.parentInfo.InitialStates = xstates;
                }
                else {
                    // Build a standalone tree, with this constructor as its root
                    if (ndConstr.NodeType != QilNodeType.Choice)
                        this.parentInfo.InitialStates = this.parentInfo.FinalStates = PossibleXmlStates.WithinSequence;

                    // Don't stream Rtf; fully cache the Rtf and copy it into any containing tree in order to simplify XmlILVisitor.VisitRtfCtor
                    if (ndConstr.NodeType != QilNodeType.RtfCtor)
                        this.parentInfo.ConstructMethod = XmlILConstructMethod.WriterThenIterator;
                }

                // Set withinElem = true if analyzing element content
                this.withinElem = (ndConstr.NodeType == QilNodeType.ElementCtor);

                switch (ndConstr.NodeType) {
                    case QilNodeType.DocumentCtor: this.xstates = PossibleXmlStates.WithinContent; break;
                    case QilNodeType.ElementCtor: this.xstates = PossibleXmlStates.EnumAttrs; break;
                    case QilNodeType.AttributeCtor: this.xstates = PossibleXmlStates.WithinAttr; break;
                    case QilNodeType.NamespaceDecl: Debug.Assert(ndContent == null); break;
                    case QilNodeType.TextCtor: Debug.Assert(ndContent == null); break;
                    case QilNodeType.RawTextCtor: Debug.Assert(ndContent == null); break;
                    case QilNodeType.CommentCtor: this.xstates = PossibleXmlStates.WithinComment; break;
                    case QilNodeType.PICtor: this.xstates = PossibleXmlStates.WithinPI; break;
                    case QilNodeType.XsltCopy: this.xstates = PossibleXmlStates.Any; break;
                    case QilNodeType.XsltCopyOf: Debug.Assert(ndContent == null); break;
                    case QilNodeType.Function: this.xstates = this.parentInfo.InitialStates; break;
                    case QilNodeType.RtfCtor: this.xstates = PossibleXmlStates.WithinContent; break;
                    case QilNodeType.Choice: this.xstates = PossibleXmlStates.Any; break;
                    default: Debug.Assert(false, ndConstr.NodeType + " is not handled by XmlILStateAnalyzer."); break;
                }

                if (ndContent != null)
                    ndContent = AnalyzeContent(ndContent);

                if (ndConstr.NodeType == QilNodeType.Choice)
                    AnalyzeChoice(ndConstr as QilChoice, this.parentInfo);

                // Since Function will never be another node's content, set its final states here
                if (ndConstr.NodeType == QilNodeType.Function)
                    this.parentInfo.FinalStates = this.xstates;
            }

            return ndContent;
        }
 /// <summary>
 /// Default to worst possible construction information.
 /// </summary>
 private XmlILConstructInfo(QilNodeType nodeType) {
     this.nodeType = nodeType;
     this.xstatesInitial = this.xstatesFinal = PossibleXmlStates.Any;
     this.xstatesBeginLoop = this.xstatesEndLoop = PossibleXmlStates.None;
     this.isNmspInScope = false;
     this.mightHaveNmsp = true;
     this.mightHaveAttrs = true;
     this.mightHaveDupAttrs = true;
     this.mightHaveNmspAfterAttrs = true;
     this.constrMeth = XmlILConstructMethod.Iterator;
     this.parentInfo = null;
 }