internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.ParameterExpression enumerator,
Expression list, Expression left, MSAst.Expression body,
Statement else_, SourceSpan span, SourceLocation header,
MSAst.LabelTarget breakLabel, MSAst.LabelTarget continueLabel, bool isStatement) {
// enumerator, isDisposable = Dynamic(GetEnumeratorBinder, list)
MSAst.Expression init = Ast.Assign(
enumerator,
new PythonDynamicExpression1<KeyValuePair<IEnumerator, IDisposable>>(
Binders.UnaryOperationBinder(
parent.GlobalParent.PyContext,
PythonOperationKind.GetEnumeratorForIteration
),
parent.GlobalParent.CompilationMode,
AstUtils.Convert(list, typeof(object))
)
);
// while enumerator.MoveNext():
// left = enumerator.Current
// body
// else:
// else
MSAst.Expression ls = AstUtils.Loop(
parent.GlobalParent.AddDebugInfo(
Ast.Call(
Ast.Property(
enumerator,
typeof(KeyValuePair<IEnumerator, IDisposable>).GetProperty("Key")
),
typeof(IEnumerator).GetMethod("MoveNext")
),
left.Span
),
null,
Ast.Block(
left.TransformSet(
SourceSpan.None,
Ast.Call(
Ast.Property(
enumerator,
typeof(KeyValuePair<IEnumerator, IDisposable>).GetProperty("Key")
),
typeof(IEnumerator).GetProperty("Current").GetGetMethod()
),
PythonOperationKind.None
),
body,
isStatement ? UpdateLineNumber(parent.GlobalParent.IndexToLocation(list.StartIndex).Line) : AstUtils.Empty(),
AstUtils.Empty()
),
else_,
breakLabel,
continueLabel
);
return Ast.Block(
init,
Ast.TryFinally(
ls,
Ast.Call(AstMethods.ForLoopDispose, enumerator)
)
);
}