System.Xml.Xsl.IlGen.XmlILVisitor.Sequence C# (CSharp) Method

Sequence() private method

Generate code for QilNodeType.Sequence, when sort-merging to retain document order is not necessary.
private Sequence ( QilList ndSeq ) : void
ndSeq System.Xml.Xsl.Qil.QilList
return void
        private void Sequence(QilList ndSeq) {
            LocalBuilder locIdx, locList;
            Label lblStart, lblNext, lblOnEnd = new Label();
            Label[] arrSwitchLabels;
            int i;
            Type itemStorageType = GetItemStorageType(ndSeq);
            Debug.Assert(XmlILConstructInfo.Read(ndSeq).ConstructMethod == XmlILConstructMethod.Iterator, "This method should only be called if items in list are pulled from a code iterator.");

            // Singleton list is a special case if in addition to the singleton there are warnings or errors which should be executed
            if (ndSeq.XmlType.IsSingleton) {
                foreach (QilNode nd in ndSeq) {
                    // Generate nested iterator's code
                    if (nd.XmlType.IsSingleton) {
                        NestedVisitEnsureStack(nd);
                    }
                    else {
                        lblOnEnd = this.helper.DefineLabel();
                        NestedVisit(nd, lblOnEnd);
                        this.iterCurr.DiscardStack();
                        this.helper.MarkLabel(lblOnEnd);
                    }
                }
                this.iterCurr.Storage = StorageDescriptor.Stack(itemStorageType, false);
            }
            else {
                // Type itemList;
                // int idxList;
                locList = this.helper.DeclareLocal("$$$itemList", itemStorageType);
                locIdx = this.helper.DeclareLocal("$$$idxList", typeof(int));

                arrSwitchLabels = new Label[ndSeq.Count];
                lblStart = this.helper.DefineLabel();

                for (i = 0; i < ndSeq.Count; i++) {
                    // LabelOnEnd[i - 1]:
                    // When previous nested iterator is exhausted, it should jump to this (the next) iterator
                    if (i != 0)
                        this.helper.MarkLabel(lblOnEnd);

                    // Create new LabelOnEnd for all but the last iterator, which jumps back to parent iterator when exhausted
                    if (i == ndSeq.Count - 1)
                        lblOnEnd = this.iterCurr.GetLabelNext();
                    else
                        lblOnEnd = this.helper.DefineLabel();

                    // idxList = [i];
                    this.helper.LoadInteger(i);
                    this.helper.Emit(OpCodes.Stloc, locIdx);

                    // Generate nested iterator's code
                    NestedVisit(ndSeq[i], lblOnEnd);

                    // Result of list should be saved to a common type and location
                    this.iterCurr.EnsureItemStorageType(ndSeq[i].XmlType, itemStorageType);
                    this.iterCurr.EnsureLocalNoCache(locList);

                    // Switch statement will jump to nested iterator's LabelNext
                    arrSwitchLabels[i] = this.iterNested.GetLabelNext();

                    // IL's rules prevent OpCodes.Br here
                    // goto LabelStart;
                    this.helper.EmitUnconditionalBranch(OpCodes.Brtrue, lblStart);
                }

                // LabelNext:
                lblNext = this.helper.DefineLabel();
                this.helper.MarkLabel(lblNext);

                // switch (idxList)
                //   case 0: goto LabelNext1;
                //   ...
                //   case N-1: goto LabelNext[N];
                this.helper.Emit(OpCodes.Ldloc, locIdx);
                this.helper.Emit(OpCodes.Switch, arrSwitchLabels);

                // LabelStart:
                this.helper.MarkLabel(lblStart);

                this.iterCurr.SetIterator(lblNext, StorageDescriptor.Local(locList, itemStorageType, false));
            }
        }
XmlILVisitor