bool IBoundExprVisitor <bool> .Visit(BoundIfExpr expr) { // evaluate the condition expr.Condition.Accept(this); mJumpTable.JumpIfFalse("else"); // thenBody expr.ThenBody.Accept(this); if (expr.ElseBody == null) { // jump past it mJumpTable.PatchJump("else"); } else { // jump to end mJumpTable.Jump("end"); // elseBody mJumpTable.PatchJump("else"); expr.ElseBody.Accept(this); // end mJumpTable.PatchJump("end"); } return(true); }
IBoundExpr IUnboundExprVisitor<IBoundExpr>.Visit(IfExpr expr) { var bound = new BoundIfExpr( expr.Condition.Accept(this), expr.ThenBody.Accept(this), (expr.ElseBody == null) ? null : expr.ElseBody.Accept(this)); if (bound.Condition.Type != Decl.Bool) { throw new CompileException(expr.Position, String.Format( "Condition of if/then/else is returning type {0} but should be Bool.", bound.Condition.Type)); } if (bound.ElseBody != null) { // has an else, so make sure both arms match if (!DeclComparer.TypesMatch(bound.ThenBody.Type, bound.ElseBody.Type)) { throw new CompileException(expr.Position, String.Format( "Branches of if/then/else do not return the same type. Then arm returns {0} while else arm returns {1}.", bound.ThenBody.Type, bound.ElseBody.Type)); } } else { // no else, so make the then body doesn't return a value if ((bound.ThenBody.Type != Decl.Unit) && (bound.ThenBody.Type != Decl.EarlyReturn)) { throw new CompileException(expr.Position, String.Format( "Body of if/then is returning type {0} but must be Unit (or a return) if there is no else branch.", bound.ThenBody.Type)); } } return bound; }