public override void VisitFor(BoundFor node) { // Rules for for: // * _branch stays default when IsTrue(Test); otherwise _branch // becomes a fork; // * Target for break/continue; // * Increment is only executed when the default branch reaches // the end or a continue was executed. // Initialization and test are executed on the current branch. Visit(node.Initialization); Visit(node.Test); var block = new Block(_branch, FindLabel(node), true, true, null); _branch = block.Branch.Fork(); PushBlock(block); Visit(node.Body); bool wasKilled = _branch.IsKilled; // Only visit the increment when then default branch flows there // or a continue was executed. if (!_branch.IsKilled || block.ContinueTaken) { // We need to restore the branch because if the branch is // killed, but we have a continue, the test is still done on // the branch. _branch.IsKilled = false; Visit(node.Increment); } if (!wasKilled) block.JoinBranch(_branch); // Create an extra empty branch when the test wasn't unconditional. if (node.Test != null && ToBoolean(node.Test) != true) block.JoinBranch(block.Branch.Fork()); PopBlock(block); }
public virtual void VisitFor(BoundFor node) { DefaultVisit(node); }
private void EmitFor(BoundFor node) { // Push the break and continue targets onto the stack. var breakTarget = IL.DefineLabel(GetLabel(node)); _scope.BreakTargets.Push(breakTarget); var continueTarget = IL.DefineLabel(GetLabel(node)); _scope.ContinueTargets.Push(continueTarget); // At the start of our block, we perform any initialization. if (node.Initialization != null) EmitStatement(node.Initialization); // If we have a test, we perform the test at the start of every // iteration. var startTarget = IL.DefineLabel(); IL.MarkLabel(startTarget); if (node.Test != null) EmitTest(node.Test, breakTarget.Label, true); // Add the body. EmitStatement(node.Body); // Increment is done at the end. IL.MarkLabel(continueTarget); if (node.Increment != null) EmitStatement(node.Increment); // Jump back to the start of the loop. IL.Emit(OpCodes.Br, startTarget); // Mark the end of the loop. IL.MarkLabel(breakTarget); // Remove the break and continue targets to make the previous ones // visible. _scope.BreakTargets.Pop(); _scope.ContinueTargets.Pop(); }