Every node is annotated with information about how it will be constructed by ILGen.
Inheritance: IQilAnnotation
示例#1
0
        /// <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;
                }
            }
        }
示例#2
0
        /// <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;
        }
示例#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
        /// <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);
        }
示例#5
0
        /// <summary>
        /// Analyze list.
        /// </summary>
        protected virtual void AnalyzeSequence(QilList ndSeq, XmlILConstructInfo info)
        {
            // Ensure that construct method is Writer
            info.ConstructMethod = XmlILConstructMethod.Writer;

            // Analyze each item in the list
            for (int idx = 0; idx < ndSeq.Count; idx++)
            {
                ndSeq[idx] = AnalyzeContent(ndSeq[idx]);
            }
        }
示例#6
0
 /// <summary>
 /// Perform tail-call analysis on the functions in the specified QilExpression.
 /// </summary>
 public static void Analyze(QilExpression qil)
 {
     foreach (QilFunction ndFunc in qil.FunctionList)
     {
         // Only analyze functions which are pushed to the writer, since otherwise code
         // is generated after the call instruction in order to process cached results
         if (XmlILConstructInfo.Read(ndFunc).ConstructMethod == XmlILConstructMethod.Writer)
         {
             AnalyzeDefinition(ndFunc.Definition);
         }
     }
 }
示例#7
0
 /// <summary>
 /// Default to worst possible construction information.
 /// </summary>
 private XmlILConstructInfo(QilNodeType nodeType)
 {
     _nodeType                = nodeType;
     _xstatesInitial          = _xstatesFinal = PossibleXmlStates.Any;
     _xstatesBeginLoop        = _xstatesEndLoop = PossibleXmlStates.None;
     _isNmspInScope           = false;
     _mightHaveNmsp           = true;
     _mightHaveAttrs          = true;
     _mightHaveDupAttrs       = true;
     _mightHaveNmspAfterAttrs = true;
     _constrMeth              = XmlILConstructMethod.Iterator;
     _parentInfo              = null;
 }
示例#8
0
        /// <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;
            }
        }
示例#9
0
        /// <summary>
        /// Analyze copying items.
        /// </summary>
        protected override void AnalyzeCopy(QilNode ndCopy, XmlILConstructInfo info)
        {
            if (ndCopy.NodeType == QilNodeType.AttributeCtor)
            {
                AnalyzeAttributeCtor(ndCopy as QilBinary, info);
            }
            else
            {
                CheckAttributeNamespaceConstruct(ndCopy.XmlType);
            }

            base.AnalyzeCopy(ndCopy, info);
        }
示例#10
0
        /// <summary>
        /// Create and initialize XmlILConstructInfo annotation for the specified node.
        /// </summary>
        public static XmlILConstructInfo Write(QilNode nd)
        {
            XmlILAnnotation    ann        = XmlILAnnotation.Write(nd);
            XmlILConstructInfo constrInfo = ann.ConstructInfo;

            if (constrInfo == null || constrInfo._isReadOnly)
            {
                constrInfo        = new XmlILConstructInfo(nd.NodeType);
                ann.ConstructInfo = constrInfo;
            }

            return(constrInfo);
        }
        /// <summary>
        /// Analyze copying items.
        /// </summary>
        protected override void AnalyzeCopy(QilNode ndCopy, XmlILConstructInfo info)
        {
            if (ndCopy.NodeType == QilNodeType.AttributeCtor)
            {
                QilBinary?binaryNode = ndCopy as QilBinary;
                Debug.Assert(binaryNode != null);
                AnalyzeAttributeCtor(binaryNode, info);
            }
            else
            {
                CheckAttributeNamespaceConstruct(ndCopy.XmlType !);
            }

            base.AnalyzeCopy(ndCopy, info);
        }
        /// <summary>
        /// Analyze attribute constructor.
        /// </summary>
        private void AnalyzeAttributeCtor(QilBinary ndAttr, XmlILConstructInfo info)
        {
            if (ndAttr.Left.NodeType == QilNodeType.LiteralQName)
            {
                QilName?ndName = ndAttr.Left as QilName;
                Debug.Assert(ndName != null);
                XmlQualifiedName qname;
                int idx;

                // This attribute might be constructed on the parent element
                this.parentInfo !.MightHaveAttributes = true;

                // Check to see whether this attribute is a duplicate of a previous attribute
                if (!this.parentInfo.MightHaveDuplicateAttributes)
                {
                    qname = new XmlQualifiedName(_attrNames.Add(ndName.LocalName), _attrNames.Add(ndName.NamespaceUri));

                    for (idx = 0; idx < _dupAttrs.Count; idx++)
                    {
                        XmlQualifiedName qnameDup = (XmlQualifiedName)_dupAttrs[idx] !;

                        if ((object)qnameDup.Name == (object)qname.Name && (object)qnameDup.Namespace == (object)qname.Namespace)
                        {
                            // A duplicate attribute has been encountered
                            this.parentInfo.MightHaveDuplicateAttributes = true;
                        }
                    }

                    if (idx >= _dupAttrs.Count)
                    {
                        // This is not a duplicate attribute, so add it to the set
                        _dupAttrs.Add(qname);
                    }
                }

                // The attribute's namespace might need to be declared
                if (!info.IsNamespaceInScope)
                {
                    this.parentInfo.MightHaveNamespaces = true;
                }
            }
            else
            {
                // Attribute prefix and namespace are not known at compile-time
                CheckAttributeNamespaceConstruct(ndAttr.XmlType !);
            }
        }
        /// <summary>
        /// Get ConstructInfo annotation for the specified node.  Lazily create if necessary.
        /// </summary>
        public static XmlILConstructInfo Read(QilNode nd) {
            XmlILAnnotation ann = nd.Annotation as XmlILAnnotation;
            XmlILConstructInfo constrInfo = (ann != null) ? ann.ConstructInfo : null;

            if (constrInfo == null) {
                if (Default == null) {
                    constrInfo = new XmlILConstructInfo(QilNodeType.Unknown);
                    constrInfo.isReadOnly = true;

                    Default = constrInfo;
                }
                else {
                    constrInfo = Default;
                }
            }

            return constrInfo;
        }
示例#14
0
        /// <summary>
        /// Analyze the content argument of the ElementCtor.  Try to eliminate as many runtime checks as possible,
        /// both for the ElementCtor and for content constructors.
        /// </summary>
        public override QilNode Analyze(QilNode ndElem, QilNode ndContent)
        {
            Debug.Assert(ndElem.NodeType == QilNodeType.ElementCtor);
            this.parentInfo = XmlILConstructInfo.Write(ndElem);

            // Start by assuming that these properties are false (they default to true, but analyzer might be able to
            // prove they are really false).
            this.parentInfo.MightHaveNamespacesAfterAttributes = false;
            this.parentInfo.MightHaveAttributes          = false;
            this.parentInfo.MightHaveDuplicateAttributes = false;

            // The element's namespace might need to be declared
            this.parentInfo.MightHaveNamespaces = !this.parentInfo.IsNamespaceInScope;

            // Clear list of duplicate attributes
            _dupAttrs.Clear();

            return(base.Analyze(ndElem, ndContent));
        }
示例#15
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);
            }
        }
示例#16
0
        /// <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;
            }
        }
示例#17
0
        /// <summary>
        /// Get ConstructInfo annotation for the specified node.  Lazily create if necessary.
        /// </summary>
        public static XmlILConstructInfo Read(QilNode nd)
        {
            XmlILAnnotation    ann        = nd.Annotation as XmlILAnnotation;
            XmlILConstructInfo constrInfo = (ann != null) ? ann.ConstructInfo : null;

            if (constrInfo == null)
            {
                if (s_default == null)
                {
                    constrInfo             = new XmlILConstructInfo(QilNodeType.Unknown);
                    constrInfo._isReadOnly = true;

                    s_default = constrInfo;
                }
                else
                {
                    constrInfo = s_default;
                }
            }

            return(constrInfo);
        }
示例#18
0
        /// <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 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);
        }
        /// <summary>
        /// Analyze copying items.
        /// </summary>
        protected override void AnalyzeCopy(QilNode ndCopy, XmlILConstructInfo info) {
            if (ndCopy.NodeType == QilNodeType.AttributeCtor) {
                AnalyzeAttributeCtor(ndCopy as QilBinary, info);
            }
            else {
                CheckAttributeNamespaceConstruct(ndCopy.XmlType);
            }

            base.AnalyzeCopy(ndCopy, info);
        }
        /// <summary>
        /// Analyze list.
        /// </summary>
        protected virtual void AnalyzeSequence(QilList ndSeq, XmlILConstructInfo info) {
            // Ensure that construct method is Writer
            info.ConstructMethod = XmlILConstructMethod.Writer;

            // Analyze each item in the list
            for (int idx = 0; idx < ndSeq.Count; idx++)
                ndSeq[idx] = AnalyzeContent(ndSeq[idx]);
        }
        /// <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;
        }
示例#23
0
 /// <summary>
 /// Returns true if the specified element should cache attributes.
 /// </summary>
 private bool ElementCachesAttributes(XmlILConstructInfo info)
 {
     // Attributes will be cached if namespaces might be constructed after the attributes
     return info.MightHaveDuplicateAttributes || info.MightHaveNamespacesAfterAttributes;
 }
        /// <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 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);
        }
        /// <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);
        }
示例#27
0
        /// <summary>
        /// Recursively analyze content.  Return "nd" or a replacement for it.
        /// </summary>
        protected virtual QilNode AnalyzeContent(QilNode nd)
        {
            XmlILConstructInfo info;
            QilNode            ndChild;

            // Handle special node-types that are replaced
            switch (nd.NodeType)
            {
            case QilNodeType.For:
            case QilNodeType.Let:
            case QilNodeType.Parameter:
                // Iterator references are shared and cannot be annotated directly with ConstructInfo,
                // so wrap them with Nop node.
                nd = this.fac.Nop(nd);
                break;
            }

            // Get node's ConstructInfo annotation
            info = XmlILConstructInfo.Write(nd);

            // Set node's guaranteed parent constructor
            info.ParentInfo = this.parentInfo;

            // Construct all content using the Writer
            info.PushToWriterLast = true;

            // Set states that are possible before expression is constructed
            info.InitialStates = this.xstates;

            switch (nd.NodeType)
            {
            case QilNodeType.Loop: AnalyzeLoop(nd as QilLoop, info); break;

            case QilNodeType.Sequence: AnalyzeSequence(nd as QilList, info); break;

            case QilNodeType.Conditional: AnalyzeConditional(nd as QilTernary, info); break;

            case QilNodeType.Choice: AnalyzeChoice(nd as QilChoice, info); break;

            case QilNodeType.Error:
            case QilNodeType.Warning:
                // Ensure that construct method is Writer
                info.ConstructMethod = XmlILConstructMethod.Writer;
                break;

            case QilNodeType.Nop:
                ndChild = (nd as QilUnary).Child;
                switch (ndChild.NodeType)
                {
                case QilNodeType.For:
                case QilNodeType.Let:
                case QilNodeType.Parameter:
                    // Copy iterator items as content
                    AnalyzeCopy(nd, info);
                    break;

                default:
                    // Ensure that construct method is Writer and recursively analyze content
                    info.ConstructMethod = XmlILConstructMethod.Writer;
                    AnalyzeContent(ndChild);
                    break;
                }
                break;

            default:
                AnalyzeCopy(nd, info);
                break;
            }

            // Set states that are possible after expression is constructed
            info.FinalStates = this.xstates;

            return(nd);
        }
示例#28
0
        /// <summary>
        /// Return true if a runtime check needs to be made in order to transition into the EnumAttrs state.
        /// </summary>
        private bool CheckEnumAttrs(XmlILConstructInfo info)
        {
            switch (info.InitialStates)
            {
                case PossibleXmlStates.WithinSequence:
                case PossibleXmlStates.EnumAttrs:
                    // Transition to EnumAttrs can be ensured at compile-time
                    return false;
            }

            return true;
        }
示例#29
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);
        }
示例#30
0
        /// <summary>
        /// Determine whether an ElementCtor, AttributeCtor, or NamespaceDecl's namespace is already declared.  If it is,
        /// set the IsNamespaceInScope property to True.  Otherwise, add the namespace to the set of in-scope namespaces if
        /// addInScopeNmsp is True.  Return false if the name is computed or is invalid.
        /// </summary>
        private bool CheckNamespaceInScope(QilBinary nd)
        {
            QilName       ndName;
            string        prefix, ns, prefixExisting, nsExisting;
            XPathNodeType nodeType;

            switch (nd.NodeType)
            {
            case QilNodeType.ElementCtor:
            case QilNodeType.AttributeCtor:
                ndName = nd.Left as QilName;
                if (ndName != null)
                {
                    prefix   = ndName.Prefix;
                    ns       = ndName.NamespaceUri;
                    nodeType = (nd.NodeType == QilNodeType.ElementCtor) ? XPathNodeType.Element : XPathNodeType.Attribute;
                    break;
                }

                // Not a literal name, so return false
                return(false);

            default:
                Debug.Assert(nd.NodeType == QilNodeType.NamespaceDecl);
                prefix   = (string)(QilLiteral)nd.Left;
                ns       = (string)(QilLiteral)nd.Right;
                nodeType = XPathNodeType.Namespace;
                break;
            }

            // Attribute with null namespace and xmlns:xml are always in-scope
            if (nd.NodeType == QilNodeType.AttributeCtor && ns.Length == 0 ||
                prefix == "xml" && ns == XmlReservedNs.NsXml)
            {
                XmlILConstructInfo.Write(nd).IsNamespaceInScope = true;
                return(true);
            }

            // Don't process names that are invalid
            if (!ValidateNames.ValidateName(prefix, string.Empty, ns, nodeType, ValidateNames.Flags.CheckPrefixMapping))
            {
                return(false);
            }

            // Atomize names
            prefix = _nsmgr.NameTable.Add(prefix);
            ns     = _nsmgr.NameTable.Add(ns);

            // Determine whether namespace is already in-scope
            for (int iNmsp = 0; iNmsp < _cntNmsp; iNmsp++)
            {
                _nsmgr.GetNamespaceDeclaration(iNmsp, out prefixExisting, out nsExisting);

                // If prefix is already declared,
                if ((object)prefix == (object)prefixExisting)
                {
                    // Then if the namespace is the same, this namespace is redundant
                    if ((object)ns == (object)nsExisting)
                    {
                        XmlILConstructInfo.Write(nd).IsNamespaceInScope = true;
                    }

                    // Else quit searching, because any further matching prefixes will be hidden (not in-scope)
                    Debug.Assert(nd.NodeType != QilNodeType.NamespaceDecl || !_nsmgr.HasNamespace(prefix) || _nsmgr.LookupNamespace(prefix) == ns,
                                 "Compilers must ensure that namespace declarations do not conflict with the namespace used by the element constructor.");
                    break;
                }
            }

            // If not in-scope, then add if it's allowed
            if (_addInScopeNmsp)
            {
                _nsmgr.AddNamespace(prefix, ns);
                _cntNmsp++;
            }

            return(true);
        }
        /// <summary>
        /// Create and initialize XmlILConstructInfo annotation for the specified node.
        /// </summary>
        public static XmlILConstructInfo Write(QilNode nd) {
            XmlILAnnotation ann = XmlILAnnotation.Write(nd);
            XmlILConstructInfo constrInfo = ann.ConstructInfo;

            if (constrInfo == null || constrInfo.isReadOnly) {
                constrInfo = new XmlILConstructInfo(nd.NodeType);
                ann.ConstructInfo = constrInfo;
            }

            return constrInfo;
        }
        /// <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>
        /// Analyze attribute constructor.
        /// </summary>
        private void AnalyzeAttributeCtor(QilBinary ndAttr, XmlILConstructInfo info) {
            if (ndAttr.Left.NodeType == QilNodeType.LiteralQName) {
                QilName ndName = ndAttr.Left as QilName;
                XmlQualifiedName qname;
                int idx;

                // This attribute might be constructed on the parent element
                this.parentInfo.MightHaveAttributes = true;

                // Check to see whether this attribute is a duplicate of a previous attribute
                if (!this.parentInfo.MightHaveDuplicateAttributes) {
                    qname = new XmlQualifiedName(this.attrNames.Add(ndName.LocalName), this.attrNames.Add(ndName.NamespaceUri));

                    for (idx = 0; idx < this.dupAttrs.Count; idx++) {
                        XmlQualifiedName qnameDup = (XmlQualifiedName) this.dupAttrs[idx];

                        if ((object) qnameDup.Name == (object) qname.Name && (object) qnameDup.Namespace == (object) qname.Namespace) {
                            // A duplicate attribute has been encountered
                            this.parentInfo.MightHaveDuplicateAttributes = true;
                        }
                    }

                    if (idx >= this.dupAttrs.Count) {
                        // This is not a duplicate attribute, so add it to the set
                        this.dupAttrs.Add(qname);
                    }
                }

                // The attribute's namespace might need to be declared
                if (!info.IsNamespaceInScope)
                    this.parentInfo.MightHaveNamespaces = true;
            }
            else {
                // Attribute prefix and namespace are not known at compile-time
                CheckAttributeNamespaceConstruct(ndAttr.XmlType);
            }
        }
 /// <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;
 }
        /// <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;
            }
        }
示例#36
0
        /// <summary>
        /// Returns true if the specified node's owner element might have local namespaces added to it
        /// after attributes have already been added.
        /// </summary>
        private bool MightHaveNamespacesAfterAttributes(XmlILConstructInfo info)
        {
            // Get parent element
            if (info != null)
                info = info.ParentElementInfo;

            // If a parent element has not been statically identified, then assume that the runtime
            // element will have namespaces added after attributes.
            if (info == null)
                return true;

            return info.MightHaveNamespacesAfterAttributes;
        }
        /// <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;
        }