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 })); }
//### bob: for some reason, the binder doesn't work here. once that's fixed, // get rid of the explicit bound arg /// <summary> /// Binds this expression using the given binder to convert the unbound /// form to the bound one. /// </summary> /// <param name="binder">A binder to convert from unbound to bound form.</param> public void Bind(BindingContext context, IUnboundExprVisitor <IBoundExpr> binder) { if (binder == null) { throw new ArgumentNullException("binder"); } if (Unbound == null) { throw new InvalidOperationException("Cannot bind an Expr that is already bound."); } //### bob: doing this here is a hack. need to find a clean location for the // multi-pass compiling. if we get away from a separate bound and unbound expr and // just use more mutability, this whole class will go away. // desugar var letTransformer = new LetTransformer(context.NameGenerator); var unbound = Unbound.AcceptTransformer(letTransformer); var loopTransformer = new LoopTransformer(context.NameGenerator); unbound = unbound.AcceptTransformer(loopTransformer); var expandTuple = new ExpandTupleAssignment(context.NameGenerator); unbound = unbound.AcceptTransformer(expandTuple); Bound = unbound.Accept(binder); // discard the unbound one now. makes sure we're clear on what state we expect // the expression to be in. Unbound = null; }
public IBoundExpr CreateCall(IBoundExpr arg) { if (mStruct.Fields.Count > 1) { // the struct has multiple fields, the arg tuple *is* the struct // so we just return it with the right type return(new BoundTupleExpr(((BoundTupleExpr)arg).Fields, mStruct)); } else if (mStruct.Fields.Count == 1) { // the struct has only one field, the arg will just be a value. // in that case, we need to hoist it into a tuple to make it // properly a reference type. //### opt: this is really only needed for mutable single-field // structs. for immutable ones, pass by reference and pass by value // are indistinguishable. return(new BoundTupleExpr(new IBoundExpr[] { arg }, mStruct)); } else { // for an empty struct, just include a dummy value //### bob: this is gross return(new BoundTupleExpr(new IBoundExpr[] { new IntExpr(0) }, mStruct)); } }
public IBoundExpr CreateCall(IBoundExpr arg) { //### opt: unions with no value don't need to be references // could just put the value in place var loadCase = new LoadExpr(arg, Decl.Int, 0); return Intrinsic.EqualInt(loadCase, new IntExpr(mCase.Index)); }
public IBoundExpr CreateCall(IBoundExpr arg) { //### opt: unions with no value don't need to be references // could just put the value in place var loadCase = new LoadExpr(arg, Decl.Int, 0); return(Intrinsic.EqualInt(loadCase, new IntExpr(mCase.Index))); }
public Expr(IBoundExpr bound) { if (bound == null) { throw new ArgumentNullException("bound"); } Bound = bound; }
public LoadExpr(IBoundExpr structure, IBoundDecl type, int index) { if (structure == null) { throw new ArgumentNullException("structure"); } if (type == null) { throw new ArgumentNullException("type"); } Struct = structure; Type = type; Index = index; }
public IBoundExpr CreateCall(IBoundExpr arg) { var fields = new List <IBoundExpr>(); // add the case tag fields.Add(new IntExpr(mCase.Index)); // add the value, if any if (!(arg is UnitExpr)) { fields.Add(arg); } // create the structure return(new BoundTupleExpr(fields, mCase.Union)); }
public IBoundExpr CreateCall(IBoundExpr arg) { var fields = new List<IBoundExpr>(); // add the case tag fields.Add(new IntExpr(mCase.Index)); // add the value, if any if (!(arg is UnitExpr)) { fields.Add(arg); } // create the structure return new BoundTupleExpr(fields, mCase.Union); }
public static IBoundExpr PrependArg(this IBoundExpr arg, IBoundExpr value) { if (arg is UnitExpr) { // no arg, so just use the value return value; } var tuple = arg as BoundTupleExpr; if (tuple != null) { // multiple args, so just add another var newArg = new BoundTupleExpr(tuple.Fields); newArg.Fields.Insert(0, value); return newArg; } // single arg, so create a tuple return new BoundTupleExpr(new IBoundExpr[] { value, arg }); }
public IBoundExpr ResolveFunction(Function function, Position position, string name, IList <IUnboundDecl> typeArgs, IBoundExpr arg) { if (arg == null) { throw new ArgumentNullException("arg"); } // look up the function var callable = Compiler.Functions.Find(this, name, typeArgs, arg.Type); if (callable == null) { throw new CompileException(position, String.Format("Could not resolve name {0}.", Callable.UniqueName(name, null, arg.Type))); } return(callable.CreateCall(arg)); }
public static IBoundExpr PrependArg(this IBoundExpr arg, IBoundExpr value) { if (arg is UnitExpr) { // no arg, so just use the value return(value); } var tuple = arg as BoundTupleExpr; if (tuple != null) { // multiple args, so just add another var newArg = new BoundTupleExpr(tuple.Fields); newArg.Fields.Insert(0, value); return(newArg); } // single arg, so create a tuple return(new BoundTupleExpr(new IBoundExpr[] { value, arg })); }
public LoadExpr(IBoundExpr structure, Field field) : this(structure, field.Type.Bound, field.Index) { }
public IBoundExpr CreateCall(IBoundExpr arg) { return new LoadExpr(arg, mCase.ValueType.Bound, 1); }
/// <summary> /// Resolves and binds a reference to a name. /// </summary> /// <param name="function">The function being compiled.</param> /// <param name="scope">The scope in which the name is being bound.</param> /// <param name="name">The name being resolved. May or may not be fully-qualified.</param> /// <param name="typeArgs">The type arguments being applied to the name. For /// example, resolving "foo'(int, bool)" would pass in {int, bool} here.</param> /// <param name="arg">The argument being applied to the name.</param> /// <returns></returns> public IBoundExpr ResolveName(Function function, Scope scope, Position position, string name, IList <IUnboundDecl> typeArgs, IBoundExpr arg) { IBoundDecl argType = null; if (arg != null) { argType = arg.Type; } IBoundExpr resolved = null; // see if it's an argument if (function.ParamNames.Contains(name)) { // load the argument resolved = new LoadExpr(new LocalsExpr(), function.ParameterType, 0); if (function.ParamNames.Count > 1) { // function takes multiple parameters, so load it from the tuple var paramTuple = (BoundTupleType)function.ParameterType; var argIndex = (byte)function.ParamNames.IndexOf(name); resolved = new LoadExpr(resolved, paramTuple.Fields[argIndex], argIndex); } } // see if it's a local if (scope.Contains(name)) { var local = scope[name]; // just load the value resolved = new LoadExpr(new LocalsExpr(), scope[name]); } // if we resolved to a local name, handle it if (resolved != null) { if (typeArgs.Count > 0) { throw new CompileException(position, "Cannot apply type arguments to a local variable or function argument."); } // if the local or argument is holding a function reference and we're passed args, call it if (argType != null) { var funcType = resolved.Type as FuncType; if (funcType != null) { // check that args match if (!DeclComparer.TypesMatch(funcType.Parameter.Bound, argType)) { throw new CompileException(position, "Argument types passed to local function reference do not match function's parameter types."); } // call it resolved = new BoundCallExpr(resolved, arg); } else { // not calling a function, so try to desugar to a __Call var callArg = new BoundTupleExpr(new IBoundExpr[] { resolved, arg }); resolved = ResolveFunction(function, position, "__Call", new IUnboundDecl[0], callArg); if (resolved == null) { throw new CompileException(position, "Cannot call a local variable or argument that is not a function reference, and could not find a matching __Call."); } } } return(resolved); } // implicitly apply () as the argument if no other argument was provided. // note that we do this *after* checking for locals because locals aren't // implicitly applied. since most locals aren't functions anyway, it won't // matter in most cases, and in cases where a local holds a function, the // user will mostly likely want to treat that function like a value: return // it, pass it around, etc. if (arg == null) { arg = new UnitExpr(Position.None); argType = arg.Type; } return(ResolveFunction(function, position, name, typeArgs, arg)); }
public IBoundExpr CreateCall(IBoundExpr arg) { var argTuple = (BoundTupleExpr)arg; return new StoreExpr(argTuple.Fields[0], mField, argTuple.Fields[1]); }
public StoreExpr(IBoundExpr structure, Field field, IBoundExpr value) { Struct = structure; Field = field; Value = value; }
public IBoundExpr CreateCall(IBoundExpr arg) { return new BoundCallExpr(new BoundFuncRefExpr(this), arg); }
public IBoundExpr CreateCall(IBoundExpr arg) { return(new LoadExpr(arg, mField)); }
public IBoundExpr CreateCall(IBoundExpr arg) { return(new BoundCallExpr(new BoundFuncRefExpr(this), arg)); }
public static IBoundExpr EqualInt(IBoundExpr left, IBoundExpr right) { var intrinsic = new Intrinsic("=", OpCode.EqualInt, FuncType.Create(Decl.Int, Decl.Int, Decl.Bool)); return(intrinsic.CreateCall(new BoundTupleExpr(new IBoundExpr[] { left, right }))); }
public ForeignCallExpr(ForeignFunction function, IBoundExpr arg) { mFunction = function; mArg = arg; }
public static IBoundExpr EqualInt(IBoundExpr left, IBoundExpr right) { var intrinsic = new Intrinsic("=", OpCode.EqualInt, FuncType.Create(Decl.Int, Decl.Int, Decl.Bool)); return intrinsic.CreateCall(new BoundTupleExpr(new IBoundExpr[] { left, right })); }
public IntrinsicExpr(Intrinsic intrinsic, IBoundExpr arg) { Intrinsic = intrinsic; Arg = arg; }
public IBoundExpr CreateCall(IBoundExpr arg) { return(new LoadExpr(arg, mCase.ValueType.Bound, 1)); }
public IBoundExpr CreateCall(IBoundExpr arg) { //### bob: constant folding goes here... return new IntrinsicExpr(this, arg); }
public IBoundExpr CreateCall(IBoundExpr arg) { var argTuple = (BoundTupleExpr)arg; return(new StoreExpr(argTuple.Fields[0], mField, argTuple.Fields[1])); }
public IBoundExpr CreateCall(IBoundExpr arg) { //### bob: constant folding goes here... return(new IntrinsicExpr(this, arg)); }
public IBoundExpr CreateCall(IBoundExpr arg) { return new LoadExpr(arg, mField); }
public IBoundExpr CreateCall(IBoundExpr arg) { return(new ForeignCallExpr(this, arg)); }