public static IUnboundExpr Match(BindingContext context, MatchExpr expr, IBoundExpr boundValue) { // validate the patterns ShapeChecker.Validate(expr, boundValue.Type); Coverage.Validate(expr, boundValue.Type); // convert the cases to vanilla if/then blocks var valueName = context.NameGenerator.Generate(); var defineValueExpr = new DefineExpr(expr.Value.Position, valueName, expr.Value, false); var valueExpr = new NameExpr(expr.Value.Position, valueName); var conditions = new List <DesugaredMatchCase>(); foreach (var matchCase in expr.Cases) { var result = new DesugaredMatchCase(); result.Condition = Match(context, boundValue.Type, matchCase.Pattern, valueExpr, result.Variables); conditions.Add(result); } // build a single compound "if" expression var ifExpr = (IUnboundExpr)null; if (expr.Cases.Count == 0) { throw new CompileException(expr.Position, "Match expression has no cases."); } else if (expr.Cases.Count == 1) { // if there is only a since case, and we've ensured exhaustivity already, // then it must match all values, so just use the body directly ifExpr = CreateCaseBody(conditions[0].Variables, expr.Cases[0].Body); } else { // go in reverse order so that we start with the trailing else and build // forward for (int i = expr.Cases.Count - 1; i >= 0; i--) { if (ifExpr == null) { // for the first popped (i.e. last appearing) case, we know it must // match because the match expression is exhaustive, so just use its // body directly ifExpr = CreateCaseBody(conditions[i].Variables, expr.Cases[i].Body); } else { var body = CreateCaseBody(conditions[i].Variables, expr.Cases[i].Body); ifExpr = new IfExpr(expr.Cases[i].Position, conditions[i].Condition, body, ifExpr); } } } return(new BlockExpr(new IUnboundExpr[] { defineValueExpr, ifExpr })); }
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; }
public virtual IUnboundExpr Transform(IfExpr expr) { return(expr); }
IUnboundExpr IUnboundExprVisitor <IUnboundExpr> .Visit(IfExpr expr) { return(Call("IfExpr", Tuple(expr.Condition.Accept(this), expr.ThenBody.Accept(this), (expr.ElseBody != null) ? expr.ElseBody.Accept(this) : Call("UnitExpr", Unit())))); }