Ejemplo n.º 1
0
        bool IBoundDeclVisitor <bool> .Visit(BoundRecordType decl)
        {
            if (!TryInferParam(decl))
            {
                RecordType paramDecl = ParamType as RecordType;
                if (paramDecl == null)
                {
                    mFailed = true;
                    return(false);
                }

                if (paramDecl.Fields.Count != decl.Fields.Count)
                {
                    mFailed = true;
                    return(false);
                }

                foreach (var pair in paramDecl.Fields.Zip(decl.Fields))
                {
                    // field names must match
                    if (pair.Item1.Key != pair.Item2.Key)
                    {
                        mFailed = true;
                        return(false);
                    }

                    mParamTypes.Push(pair.Item1.Value);
                    pair.Item2.Value.Accept(this);
                    mParamTypes.Pop();
                }
            }

            return(false);
        }
Ejemplo n.º 2
0
        IBoundExpr IUnboundExprVisitor<IBoundExpr>.Visit(RecordExpr expr)
        {
            //### bob: there's a bug here. this will convert the record into a
            // tuple where the fields are ordered by name, not by how the appear
            // in the source code. when the tuple is then compiled, the fields
            // will be evaluated in that order. this violates the left-to-right
            // evaluation a user would expect. for example:
            //
            //  Foo (->) Print "foo"
            //  Bar (->) Print "bar"
            //  Main (->)
            //      def a <- (y: Foo x: Bar)
            //  end
            //
            //  this will print "bar" then "foo".

            // bind the fields
            var fields = new Dictionary<string, IBoundExpr>();
            foreach (var field in expr.Fields)
            {
                fields.Add(field.Key, field.Value.Accept(this));
            }

            // determine the record type
            var fieldTypes = new Dictionary<string, IBoundDecl>();
            foreach (var field in fields)
            {
                fieldTypes.Add(field.Key, field.Value.Type);
            }

            var boundType = new BoundRecordType(fieldTypes);

            // discard the names and convert to just a struct
            // note that this assumes the fields will be correctly
            // iterated in sorted order
            return new BoundTupleExpr(fields.Values, boundType);
        }
Ejemplo n.º 3
0
        IBoundExpr IUnboundExprVisitor<IBoundExpr>.Visit(CallExpr expr)
        {
            var namedTarget = expr.Target as NameExpr;

            // see if it's a macro call before binding the arg
            if ((namedTarget != null) && (mContext.Compiler.MacroProcessor != null))
            {
                IUnboundExpr macroResult = mContext.Compiler.MacroProcessor.Process(namedTarget.Name, expr.Arg);

                // if it was a macro call, bind the result of it
                if (macroResult != null) return macroResult.Accept(this);
            }

            //### bob: handle array constructors. hack! should be intrinsic
            if ((namedTarget != null) && (namedTarget.Name == "ArrayOf"))
            {
                // handle ArrayOf[Int]
                if ((expr.Arg is UnitExpr) && (namedTarget.TypeArgs.Count == 1))
                {
                    return new ArrayExpr(namedTarget.Position, namedTarget.TypeArgs[0]).Accept(this);
                }

                // handle ArrayOf (1, 2, 3)
                var elements = (IEnumerable<IUnboundExpr>)(new IUnboundExpr[] { expr.Arg });
                if (expr.Arg is TupleExpr)
                {
                    elements = ((TupleExpr)expr.Arg).Fields;
                }

                return new ArrayExpr(namedTarget.Position, elements).Accept(this);
            }

            var boundArg = expr.Arg.Accept(this);

            // see if we're accessing a record field
            BoundRecordType recordType = boundArg.Type as BoundRecordType;
            if ((namedTarget != null) &&
                (recordType != null) &&
                recordType.Fields.ContainsKey(namedTarget.Name))
            {
                // find the index of the field
                //### bob: ToList() here is a gross hack.
                var index = recordType.Fields.Keys.ToList().IndexOf(namedTarget.Name);

                // bind it
                return new LoadExpr(boundArg, recordType.Fields[namedTarget.Name], index);
            }

            if (namedTarget != null)
            {
                return mContext.ResolveName(mFunction, Scope, namedTarget.Position,
                    namedTarget.Name, namedTarget.TypeArgs, boundArg);
            }

            IBoundExpr target = expr.Target.Accept(this);

            // see if we're calling a function
            FuncType funcType = target.Type as FuncType;
            if (funcType != null)
            {
                // check that args match
                if (!DeclComparer.TypesMatch(funcType.Parameter.Bound, boundArg.Type))
                {
                    throw new CompileException(expr.Position, "Argument types passed to evaluated function reference do not match function's parameter types.");
                }

                // simply apply the arg to the bound expression
                return new BoundCallExpr(target, boundArg);
            }

            // see if we're accessing a tuple field
            var tupleType = boundArg.Type as BoundTupleType;
            if ((tupleType != null) && (target.Type == Decl.Int))
            {
                var index = target as IntExpr;
                if (index == null) throw new CompileException(expr.Position, "Tuple fields can only be accessed using a literal index, not an int expression.");

                // make sure the field is in range
                if ((index.Value < 0) || (index.Value >= tupleType.Fields.Count))
                    throw new CompileException(expr.Position, String.Format("Cannot access field {0} because the tuple only has {1} fields.", index.Value, tupleType.Fields.Count));

                // bind it
                return new LoadExpr(boundArg, tupleType.Fields[index.Value], index.Value);
            }

            // not calling a function, so try to desugar to a __Call
            var callArg = new BoundTupleExpr(new IBoundExpr[] { target, boundArg });

            var call = mContext.ResolveFunction(mFunction, expr.Target.Position,
                "__Call", new IUnboundDecl[0], callArg);

            if (call != null) return call;

            throw new CompileException(expr.Position, "Target of call is not a function.");
        }