public override void VisitIf(BoundIf node) { // Rules for if: // * When IsTrue(Test), Else is not taken and Then stays the // default branch; // * When IsFalse(Test), Then is not taken and If stays the // default branch; // * Otherwise, Then and Else become a fork (even when Else // is null). bool? result = ToBoolean(node.Test); // If Test evaluates to a constant that allows us to skip // the Then, and we don't have an Else, we don't have any // work for this node. if (result == false && node.Else == null) return; // Test is executed on the default branch. Visit(node.Test); var block = new Block(_branch, null, false, false, null); PushBlock(block); if (!result.HasValue) { // Visit the Then. _branch = block.Branch.Fork(); Visit(node.Then); block.JoinBranch(_branch); // Visit the Else. Note that we always fork the branch, even // when we don't have an Else. The reason for this is that // the join algorithm correctly marks variables that are // only written to in the Then branch as not definitely // assigned. _branch = block.Branch.Fork(); if (node.Else != null) Visit(node.Else); block.JoinBranch(_branch); } else { Visit(result.Value ? node.Then : node.Else); } PopBlock(block); }
public virtual void VisitIf(BoundIf node) { DefaultVisit(node); }
private void EmitIf(BoundIf node) { var afterTarget = IL.DefineLabel(); if (node.Else != null) { var elseTarget = IL.DefineLabel(); // Jump over the Then if the test fails. EmitTest(node.Test, elseTarget, true); // Emit the Then and jump over the Else. EmitStatement(node.Then); IL.Emit(OpCodes.Br, afterTarget); // Emit the Else. IL.MarkLabel(elseTarget); EmitStatement(node.Else); } else { // Jump over the Then if the test fails. EmitTest(node.Test, afterTarget, true); // Emit the Then. EmitStatement(node.Then); } // After the whole If. IL.MarkLabel(afterTarget); }