internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) {
MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object));
MSA.Expression redoVariable = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool));
MSA.ParameterExpression unwinder;
bool isInnerLoop = gen.CurrentLoop != null;
MSA.LabelTarget breakLabel = Ast.Label();
MSA.LabelTarget continueLabel = Ast.Label();
gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel);
MSA.Expression transformedBody = gen.TransformStatements(_statements, ResultOperation.Ignore);
MSA.Expression transformedCondition = _condition.TransformCondition(gen, true);
gen.LeaveLoop();
MSA.Expression conditionPositiveStmt, conditionNegativeStmt;
if (_isWhileLoop) {
conditionPositiveStmt = AstUtils.Empty();
conditionNegativeStmt = Ast.Break(breakLabel);
} else {
conditionPositiveStmt = Ast.Break(breakLabel);
conditionNegativeStmt = AstUtils.Empty();
}
// make the loop first:
MSA.Expression loop = new AstBlock {
gen.ClearDebugInfo(),
Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)),
AstFactory.Infinite(breakLabel, continueLabel,
AstUtils.Try(
AstUtils.If(redoVariable,
Ast.Assign(redoVariable, AstUtils.Constant(false))
).ElseIf(transformedCondition,
conditionPositiveStmt
).Else(
conditionNegativeStmt
),
transformedBody,
AstUtils.Empty()
).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"),
// redo = u.IsRedo
Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)),
AstUtils.Empty()
).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak),
// result = unwinder.ReturnValue
Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)),
Ast.Break(breakLabel)
)
),
gen.ClearDebugInfo(),
AstUtils.Empty(),
};
// wrap it to try finally that updates RFC state:
if (!isInnerLoop) {
loop = AstUtils.Try(
Methods.EnterLoop.OpCall(gen.CurrentScopeVariable),
loop
).Finally(
Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable)
);
}
return Ast.Block(loop, resultVariable);
}