예제 #1
0
        /// <summary>
        /// Builds a new MethodCandidate which takes count arguments and the provided list of keyword arguments.
        ///
        /// The basic idea here is to figure out which parameters map to params or a dictionary params and
        /// fill in those spots w/ extra ParameterWrapper's.
        /// </summary>
        internal MethodCandidate MakeParamsExtended(ActionBinder binder, int count, SymbolId[] names)
        {
            Debug.Assert(BinderHelpers.IsParamsMethod(_target.Method));

            List <ParameterWrapper> newParameters = new List <ParameterWrapper>(count);
            // if we don't have a param array we'll have a param dict which is type object
            Type elementType = null;
            int  index = -1, kwIndex = -1;

            // keep track of which kw args map to a real argument, and which ones
            // map to the params dictionary.
            List <SymbolId> unusedNames       = new List <SymbolId>(names);
            List <int>      unusedNameIndexes = new List <int>();

            for (int i = 0; i < unusedNames.Count; i++)
            {
                unusedNameIndexes.Add(i);
            }

            for (int i = 0; i < _parameters.Count; i++)
            {
                ParameterWrapper pw = _parameters[i];

                if (_parameters[i].IsParamsDict)
                {
                    kwIndex = i;
                }
                else if (_parameters[i].IsParamsArray)
                {
                    elementType = pw.Type.GetElementType();
                    index       = i;
                }
                else
                {
                    for (int j = 0; j < unusedNames.Count; j++)
                    {
                        if (unusedNames[j] == _parameters[i].Name)
                        {
                            unusedNames.RemoveAt(j);
                            unusedNameIndexes.RemoveAt(j);
                            break;
                        }
                    }
                    newParameters.Add(pw);
                }
            }

            if (index != -1)
            {
                while (newParameters.Count < (count - unusedNames.Count))
                {
                    ParameterWrapper param = new ParameterWrapper(binder, elementType, SymbolId.Empty, false);
                    newParameters.Insert(System.Math.Min(index, newParameters.Count), param);
                }
            }

            if (kwIndex != -1)
            {
                foreach (SymbolId si in unusedNames)
                {
                    newParameters.Add(new ParameterWrapper(binder, typeof(object), si, false));
                }
            }
            else if (unusedNames.Count != 0)
            {
                // unbound kw args and no where to put them, can't call...
                // TODO: We could do better here because this results in an incorrect arg # error message.
                return(null);
            }

            // if we have too many or too few args we also can't call
            if (count != newParameters.Count)
            {
                return(null);
            }

            return(new MethodCandidate(_target.MakeParamsExtended(count, unusedNames.ToArray(), unusedNameIndexes.ToArray()), newParameters));
        }