Пример #1
0
        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 }));
        }
Пример #2
0
        //### 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;
        }
Пример #3
0
 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));
     }
 }
Пример #4
0
        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));
        }
Пример #5
0
        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)));
        }
Пример #6
0
        public Expr(IBoundExpr bound)
        {
            if (bound == null)
            {
                throw new ArgumentNullException("bound");
            }

            Bound = bound;
        }
Пример #7
0
        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;
        }
Пример #8
0
        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));
        }
Пример #9
0
        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);
        }
Пример #10
0
        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 });
        }
Пример #11
0
        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));
        }
Пример #12
0
        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 }));
        }
Пример #13
0
 public LoadExpr(IBoundExpr structure, Field field)
     : this(structure, field.Type.Bound, field.Index)
 {
 }
Пример #14
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return new LoadExpr(arg, mCase.ValueType.Bound, 1);
 }
Пример #15
0
        /// <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));
        }
Пример #16
0
        public IBoundExpr CreateCall(IBoundExpr arg)
        {
            var argTuple = (BoundTupleExpr)arg;

            return new StoreExpr(argTuple.Fields[0], mField, argTuple.Fields[1]);
        }
Пример #17
0
 public StoreExpr(IBoundExpr structure, Field field, IBoundExpr value)
 {
     Struct = structure;
     Field  = field;
     Value  = value;
 }
Пример #18
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return new BoundCallExpr(new BoundFuncRefExpr(this), arg);
 }
Пример #19
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return(new LoadExpr(arg, mField));
 }
Пример #20
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return(new BoundCallExpr(new BoundFuncRefExpr(this), arg));
 }
Пример #21
0
        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 })));
        }
Пример #22
0
 public ForeignCallExpr(ForeignFunction function, IBoundExpr arg)
 {
     mFunction = function;
     mArg      = arg;
 }
Пример #23
0
 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 }));
 }
Пример #24
0
 public IntrinsicExpr(Intrinsic intrinsic, IBoundExpr arg)
 {
     Intrinsic = intrinsic;
     Arg       = arg;
 }
Пример #25
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return(new LoadExpr(arg, mCase.ValueType.Bound, 1));
 }
Пример #26
0
        public IBoundExpr CreateCall(IBoundExpr arg)
        {
            //### bob: constant folding goes here...

            return new IntrinsicExpr(this, arg);
        }
Пример #27
0
        public IBoundExpr CreateCall(IBoundExpr arg)
        {
            var argTuple = (BoundTupleExpr)arg;

            return(new StoreExpr(argTuple.Fields[0], mField, argTuple.Fields[1]));
        }
Пример #28
0
        public IBoundExpr CreateCall(IBoundExpr arg)
        {
            //### bob: constant folding goes here...

            return(new IntrinsicExpr(this, arg));
        }
Пример #29
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return new LoadExpr(arg, mField);
 }
Пример #30
0
 public IBoundExpr CreateCall(IBoundExpr arg)
 {
     return(new ForeignCallExpr(this, arg));
 }