private void StartForBinding(QilIterator ndFor, OptimizerPatterns patt) {
LocalBuilder locPos = null;
Debug.Assert(ndFor.XmlType.IsSingleton);
// For expression iterator will be unnested as part of parent iterator
if (this.iterCurr.HasLabelNext)
StartNestedIterator(ndFor.Binding, this.iterCurr.GetLabelNext());
else
StartNestedIterator(ndFor.Binding);
if (patt.MatchesPattern(OptimizerPatternName.IsPositional)) {
// Need to track loop index so initialize it to 0 before starting loop
locPos = this.helper.DeclareLocal("$$$pos", typeof(int));
this.helper.Emit(OpCodes.Ldc_I4_0);
this.helper.Emit(OpCodes.Stloc, locPos);
}
// Allow base internal class to dispatch based on QilExpression node type
Visit(ndFor.Binding);
// DebugInfo: Open variable scope
// DebugInfo: Ensure that for variable is stored in a local and tag it with the user-defined name
if (this.qil.IsDebug && ndFor.DebugName != null) {
this.helper.DebugStartScope();
// Ensure that values are stored in a local variable with a user-defined name
this.iterCurr.EnsureLocalNoCache("$$$for");
this.iterCurr.Storage.LocalLocation.SetLocalSymInfo(ndFor.DebugName);
}
else {
// Ensure that values are not stored on the stack
this.iterCurr.EnsureNoStackNoCache("$$$for");
}
if (patt.MatchesPattern(OptimizerPatternName.IsPositional)) {
// Increment position
this.helper.Emit(OpCodes.Ldloc, locPos);
this.helper.Emit(OpCodes.Ldc_I4_1);
this.helper.Emit(OpCodes.Add);
this.helper.Emit(OpCodes.Stloc, locPos);
if (patt.MatchesPattern(OptimizerPatternName.MaxPosition)) {
// Short-circuit rest of loop if max position has already been reached
this.helper.Emit(OpCodes.Ldloc, locPos);
this.helper.LoadInteger((int) patt.GetArgument(OptimizerPatternArgument.MaxPosition));
this.helper.Emit(OpCodes.Bgt, this.iterCurr.ParentIterator.GetLabelNext());
}
this.iterCurr.LocalPosition = locPos;
}
EndNestedIterator(ndFor.Binding);
this.iterCurr.SetIterator(this.iterNested);
}