Ejemplo n.º 1
0
        /// <summary>
        /// Called when an application of a function is encountered.
        /// </summary>
        //$TODO: move to Analyzer.
        public static DataType Apply(
            Analyzer analyzer,
            FunType func,
            List <DataType> pos,
            IDictionary <string, DataType> hash,
            DataType kw,
            DataType star,
            Exp call)
        {
            analyzer.RemoveUncalled(func);

            if (func.Definition != null && !func.Definition.called)
            {
                analyzer.CalledFunctions++;
                func.Definition.called = true;
            }

            if (func.Definition == null)
            {
                // func without definition (possibly builtins)
                return(func.GetReturnType());
            }
            else if (call != null && analyzer.InStack(call))
            {
                // Recursive call, ignore.
                func.SelfType = null;
                return(DataType.Unknown);
            }

            if (call != null)
            {
                analyzer.pushStack(call);
            }

            var pTypes = new List <DataType>();

            // Python: bind first parameter to self type
            if (func.SelfType != null)
            {
                pTypes.Add(func.SelfType);
            }
            else if (func.Class != null)
            {
                pTypes.Add(func.Class.getCanon());
            }

            if (pos != null)
            {
                pTypes.AddRange(pos);
            }

            BindMethodAttrs(analyzer, func);

            State funcTable = new State(func.env, State.StateType.FUNCTION);

            if (func.Table.Parent != null)
            {
                funcTable.Path = func.Table.Parent.ExtendPath(analyzer, func.Definition.name.Name);
            }
            else
            {
                funcTable.Path = func.Definition.name.Name;
            }

            DataType fromType = BindParameters(analyzer,
                                               call, func.Definition, funcTable, func.Definition.parameters,
                                               func.Definition.vararg, func.Definition.kwarg,
                                               pTypes, func.defaultTypes, hash, kw, star);

            if (func.arrows.TryGetValue(fromType, out var cachedTo))
            {
                func.SelfType = null;
                return(cachedTo);
            }
            else
            {
                DataType toType = func.Definition.body.Accept(new TypeTransformer(funcTable, analyzer));
                if (MissingReturn(toType))
                {
                    analyzer.putProblem(func.Definition.name, "Function doesn't always return a value");
                    if (call != null)
                    {
                        analyzer.putProblem(call, "Call doesn't always return a value");
                    }
                }

                toType = UnionType.remove(toType, DataType.Cont);
                func.addMapping(fromType, toType);
                func.SelfType = null;
                return(toType);
            }
        }