public override void VisitWhile(BoundWhile node) { // Rules for while: // * When IsFalse(Test), we don't have any work; // * When IsTrue(Test), _branch stays the default; // * Otherwise, _branch becomes a fork; // * Target for break/continue. var result = ToBoolean(node.Test); // If Test evaluates to a constant expression false, the while // loop is never taken. if (result == false) return; // The Test is executed on the default branch. Visit(node.Test); var block = new Block(_branch, FindLabel(node), true, true, null); PushBlock(block); _branch = block.Branch.Fork(); Visit(node.Body); block.JoinBranch(_branch); // Create an empty fork to tell the Join algorithm that the // Body was an optional branch. if (result != true) block.JoinBranch(block.Branch.Fork()); PopBlock(block); }
public virtual void VisitWhile(BoundWhile node) { DefaultVisit(node); }
private void EmitWhile(BoundWhile node) { // Create the break and continue targets and push them 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 beginning of every iteration, perform the test. IL.MarkLabel(continueTarget); EmitTest(node.Test, breakTarget.Label, true); // Emit the body. EmitStatement(node.Body); // Go back to the start to perform the test again. IL.Emit(OpCodes.Br, continueTarget.Label); // After the loop. IL.MarkLabel(breakTarget); // Pop the break and continue targets to make the previous ones // available. _scope.BreakTargets.Pop(); _scope.ContinueTargets.Pop(); }