private QilNode CreateSetIterator(QilBinary ndSet, string iterName, Type iterType, MethodInfo methCreate, MethodInfo methNext) {
LocalBuilder locIter, locNav;
Label lblNext, lblCall, lblNextLeft, lblNextRight, lblInitRight;
// SetIterator iterSet;
// XPathNavigator navSet;
locIter = this.helper.DeclareLocal(iterName, iterType);
locNav = this.helper.DeclareLocal("$$$navSet", typeof(XPathNavigator));
// iterSet.Create(runtime);
this.helper.Emit(OpCodes.Ldloca, locIter);
this.helper.LoadQueryRuntime();
this.helper.Call(methCreate);
// Define labels that will be used
lblNext = this.helper.DefineLabel();
lblCall = this.helper.DefineLabel();
lblInitRight = this.helper.DefineLabel();
// Generate left nested iterator. When it is empty, it will branch to lblNext.
// goto LabelCall;
NestedVisit(ndSet.Left, lblNext);
lblNextLeft = this.iterNested.GetLabelNext();
this.iterCurr.EnsureLocal(locNav);
this.helper.EmitUnconditionalBranch(OpCodes.Brtrue, lblCall);
// Generate right nested iterator. When it is empty, it will branch to lblNext.
// LabelInitRight:
// goto LabelCall;
this.helper.MarkLabel(lblInitRight);
NestedVisit(ndSet.Right, lblNext);
lblNextRight = this.iterNested.GetLabelNext();
this.iterCurr.EnsureLocal(locNav);
this.helper.EmitUnconditionalBranch(OpCodes.Brtrue, lblCall);
// LabelNext:
this.helper.MarkLabel(lblNext);
this.helper.Emit(OpCodes.Ldnull);
this.helper.Emit(OpCodes.Stloc, locNav);
// LabelCall:
// switch (iterSet.MoveNext(nestedNested)) {
// case SetIteratorResult.NoMoreNodes: goto LabelNextCtxt;
// case SetIteratorResult.InitRightIterator: goto LabelInitRight;
// case SetIteratorResult.NeedLeftNode: goto LabelNextLeft;
// case SetIteratorResult.NeedRightNode: goto LabelNextRight;
// }
this.helper.MarkLabel(lblCall);
this.helper.Emit(OpCodes.Ldloca, locIter);
this.helper.Emit(OpCodes.Ldloc, locNav);
this.helper.Call(methNext);
// If this iterator always returns a single node, then NoMoreNodes will never be returned
// Don't expose Next label if this iterator always returns a single node
if (ndSet.XmlType.IsSingleton) {
this.helper.Emit(OpCodes.Switch, new Label[] {lblInitRight, lblNextLeft, lblNextRight});
this.iterCurr.Storage = StorageDescriptor.Current(locIter, typeof(XPathNavigator));
}
else {
this.helper.Emit(OpCodes.Switch, new Label[] {this.iterCurr.GetLabelNext(), lblInitRight, lblNextLeft, lblNextRight});
this.iterCurr.SetIterator(lblNext, StorageDescriptor.Current(locIter, typeof(XPathNavigator)));
}
return ndSet;
}