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);
 }
Beispiel #4
0
 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()))));
 }