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(DefineExpr expr) { var stores = new List<IBoundExpr>(); foreach (var define in expr.Definitions) { foreach (var name in define.Names) { if (Scope.Contains(name)) throw new CompileException(define.Position, "A local variable named \"" + name + "\" is already defined in this scope."); } var value = define.Value.Accept(this); if (define.Names.Count > 1) { // splitting a tuple var tupleType = value.Type as BoundTupleType; if (tupleType == null) throw new CompileException(define.Position, "Cannot define multiple names if the value is not a tuple."); if (tupleType.Fields.Count < define.Names.Count) throw new CompileException(define.Position, "Cannot bind more names in a define than the tuple has fields."); // define a temporary for the entire tuple expression var temp = mContext.NameGenerator.Generate(); Scope.Define(temp, value.Type, false); // split out the fields int field = 0; foreach (var name in define.Names) { Scope.Define(name, tupleType.Fields[field], expr.IsMutable); // assign it var fieldValue = new LoadExpr(value, tupleType.Fields[field], field); stores.Add(new StoreExpr(new LocalsExpr(), Scope[name], fieldValue)); field++; } } else { // just a single variable // add it to the scope Scope.Define(define.Names[0], value.Type, expr.IsMutable); // assign it stores.Add(new StoreExpr(new LocalsExpr(), Scope[define.Names[0]], value)); } } return new BoundBlockExpr(stores); }
IUnboundExpr IUnboundExprVisitor <IUnboundExpr> .Visit(DefineExpr expr) { /* * //### bob: hack temp. doesn't work with multiple defines * return Call("DefineExpr", Tuple( * Bool(expr.IsMutable), * String(expr.Definitions[0].Name), * expr.Definitions[0].Value.Accept(this))); */ throw new NotImplementedException(); }
public virtual IUnboundExpr Transform(DefineExpr expr) { return(expr); }