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