PageRenderTime 69ms CodeModel.GetById 43ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/Runtime/Microsoft.Dynamic/Runtime/BinderOps.cs

#
C# | 258 lines | 186 code | 40 blank | 32 comment | 41 complexity | 333b513c8c4f12f82d3513e12ff8eeb0 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if !CLR2
 17using System.Linq.Expressions;
 18#else
 19using Microsoft.Scripting.Ast;
 20#endif
 21
 22using System;
 23using System.Collections;
 24using System.Collections.Generic;
 25using System.Reflection;
 26using System.Diagnostics;
 27using System.Dynamic;
 28using System.Text;
 29
 30using Microsoft.Scripting.Actions;
 31using Microsoft.Scripting.Generation;
 32using Microsoft.Scripting.Utils;
 33
 34
 35namespace Microsoft.Scripting.Runtime {
 36    /// <summary>
 37    /// Helper methods that calls are generated to from the default DLR binders.
 38    /// </summary>
 39    public static class BinderOps {
 40
 41
 42        /// <summary>
 43        /// Helper function to combine an object array with a sequence of additional parameters that has been splatted for a function call.
 44        /// </summary>
 45        public static object[] GetCombinedParameters(object[] initialArgs, object additionalArgs) {
 46            IList listArgs = additionalArgs as IList;
 47            if (listArgs == null) {
 48                IEnumerable ie = additionalArgs as IEnumerable;
 49                if (ie == null) {
 50                    throw new InvalidOperationException("args must be iterable");
 51                }
 52                listArgs = new List<object>();
 53                foreach (object o in ie) {
 54                    listArgs.Add(o);
 55                }
 56            }
 57
 58            object[] res = new object[initialArgs.Length + listArgs.Count];
 59            Array.Copy(initialArgs, res, initialArgs.Length);
 60            listArgs.CopyTo(res, initialArgs.Length);
 61            return res;
 62        }
 63
 64        public static Dictionary<TKey, TValue> MakeDictionary<TKey, TValue>(string[] names, object[] values) {
 65            Debug.Assert(typeof(TKey) == typeof(string) || typeof(TKey) == typeof(object));
 66
 67            Dictionary<TKey, TValue> res = new Dictionary<TKey, TValue>();
 68            IDictionary id = (IDictionary)res;
 69            
 70            for (int i = 0; i < names.Length; i++) {
 71                id[names[i]] = values[i];
 72            }
 73
 74            return res;
 75        }
 76        
 77        public static ArgumentTypeException BadArgumentsForOperation(ExpressionType op, params object[] args) {
 78            StringBuilder message = new StringBuilder("unsupported operand type(s) for operation ");
 79            message.Append(op.ToString());
 80            message.Append(": ");
 81            string comma = "";
 82
 83            foreach (object o in args) {
 84                message.Append(comma);
 85                message.Append(CompilerHelpers.GetType(o));
 86                comma = ", ";
 87            }
 88
 89            throw new ArgumentTypeException(message.ToString());
 90        }
 91
 92
 93        // formalNormalArgumentCount - does not include FuncDefFlags.ArgList and FuncDefFlags.KwDict
 94        // defaultArgumentCount - How many arguments in the method declaration have a default value?
 95        // providedArgumentCount - How many arguments are passed in at the call site?
 96        // hasArgList - Is the method declaration of the form "foo(*argList)"?
 97        // keywordArgumentsProvided - Does the call site specify keyword arguments?
 98        public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(
 99            string methodName,
100            int formalNormalArgumentCount,
101            int defaultArgumentCount,
102            int providedArgumentCount,
103            bool hasArgList,
104            bool keywordArgumentsProvided) {
105            return TypeErrorForIncorrectArgumentCount(methodName, formalNormalArgumentCount, formalNormalArgumentCount, defaultArgumentCount, providedArgumentCount, hasArgList, keywordArgumentsProvided);
106        }
107
108        public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(
109            string methodName,
110            int minFormalNormalArgumentCount,
111            int maxFormalNormalArgumentCount,
112            int defaultArgumentCount,
113            int providedArgumentCount,
114            bool hasArgList,
115            bool keywordArgumentsProvided) {
116
117            int formalCount;
118            string formalCountQualifier;
119            string nonKeyword = keywordArgumentsProvided ? "non-keyword " : "";
120
121            if (defaultArgumentCount > 0 || hasArgList || minFormalNormalArgumentCount != maxFormalNormalArgumentCount) {
122                if (providedArgumentCount < minFormalNormalArgumentCount || maxFormalNormalArgumentCount == Int32.MaxValue) {
123                    formalCountQualifier = "at least";
124                    formalCount = minFormalNormalArgumentCount - defaultArgumentCount;
125                } else {
126                    formalCountQualifier = "at most";
127                    formalCount = maxFormalNormalArgumentCount;
128                }
129            } else if (minFormalNormalArgumentCount == 0) {
130                return ScriptingRuntimeHelpers.SimpleTypeError(string.Format("{0}() takes no arguments ({1} given)", methodName, providedArgumentCount));
131            } else {
132                formalCountQualifier = "exactly";
133                formalCount = minFormalNormalArgumentCount;
134            }
135
136            return new ArgumentTypeException(string.Format(
137                "{0}() takes {1} {2} {3}argument{4} ({5} given)",
138                                methodName, // 0
139                                formalCountQualifier, // 1
140                                formalCount, // 2
141                                nonKeyword, // 3
142                                formalCount == 1 ? "" : "s", // 4
143                                providedArgumentCount)); // 5
144        }
145
146        public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(string name, int formalNormalArgumentCount, int defaultArgumentCount, int providedArgumentCount) {
147            return TypeErrorForIncorrectArgumentCount(name, formalNormalArgumentCount, defaultArgumentCount, providedArgumentCount, false, false);
148        }
149
150        public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(string name, int expected, int received) {
151            return TypeErrorForIncorrectArgumentCount(name, expected, 0, received);
152        }
153
154        public static ArgumentTypeException TypeErrorForExtraKeywordArgument(string name, string argumentName) {
155            return new ArgumentTypeException(String.Format("{0}() got an unexpected keyword argument '{1}'", name, argumentName));
156        }
157
158        public static ArgumentTypeException TypeErrorForDuplicateKeywordArgument(string name, string argumentName) {
159            return new ArgumentTypeException(String.Format("{0}() got multiple values for keyword argument '{1}'", name, argumentName));
160        }
161
162        public static ArgumentTypeException TypeErrorForNonInferrableMethod(string name) {
163            return new ArgumentTypeException(String.Format("The type arguments for method '{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly.", name));
164        }
165
166        public static ArgumentTypeException SimpleTypeError(string message) {
167            return new ArgumentTypeException(message);
168        }
169
170        public static ArgumentTypeException InvalidSplatteeError(string name, string typeName) {
171            return new ArgumentTypeException(String.Format("{0}() argument after * must be a sequence, not {1}", name, typeName));
172        }
173
174        public static object InvokeMethod(MethodBase mb, object obj, object[] args) {
175            try {
176                return mb.Invoke(obj, args);
177            } catch (TargetInvocationException tie) {
178                throw tie.InnerException;
179            }
180        }
181
182        public static object InvokeConstructor(ConstructorInfo ci, object[] args) {
183            try {
184                return ci.Invoke(args);
185            } catch (TargetInvocationException tie) {
186                throw tie.InnerException;
187            }
188        }
189
190        // TODO: just emit this in the generated code
191        public static bool CheckDictionaryMembers(IDictionary dict, string[] names, Type[] types) {
192            if (dict.Count != names.Length) return false;
193
194            for (int i = 0; i < names.Length; i++) {
195                string name = names[i];
196
197                if (!dict.Contains(name)) {
198                    return false;
199                }
200
201                if (types != null) {
202                    if (CompilerHelpers.GetType(dict[name]) != types[i]) {
203                        return false;
204                    }
205                }
206            }
207            return true;
208        }
209
210        public static IList<string> GetStringMembers(IList<object> members) {
211            List<string> res = new List<string>();
212            foreach (object o in members) {
213                string str = o as string;
214                if (str != null) {
215                    res.Add(str);
216                }
217            }
218            return res;
219        }
220
221        /// <summary>
222        /// EventInfo.EventHandlerType getter is marked SecuritySafeCritical in CoreCLR
223        /// This method is to get to the property without using Reflection
224        /// </summary>
225        /// <param name="eventInfo"></param>
226        /// <returns></returns>
227        public static Type GetEventHandlerType(EventInfo eventInfo) {
228            ContractUtils.RequiresNotNull(eventInfo, "eventInfo");
229            return eventInfo.EventHandlerType;
230        }
231
232
233        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix
234        public static void SetEvent(EventTracker eventTracker, object value) {
235            EventTracker et = value as EventTracker;
236            if (et != null) {
237                if (et != eventTracker) {
238                    throw new ArgumentException(String.Format("expected event from {0}.{1}, got event from {2}.{3}",
239                                                eventTracker.DeclaringType.Name,
240                                                eventTracker.Name,
241                                                et.DeclaringType.Name,
242                                                et.Name));
243                }
244                return;
245            }
246
247            BoundMemberTracker bmt = value as BoundMemberTracker;
248            if (bmt == null) throw new ArgumentTypeException("expected bound event, got " + CompilerHelpers.GetType(value).Name);
249            if (bmt.BoundTo.MemberType != TrackerTypes.Event) throw new ArgumentTypeException("expected bound event, got " + bmt.BoundTo.MemberType.ToString());
250
251            if (bmt.BoundTo != eventTracker) throw new ArgumentException(String.Format("expected event from {0}.{1}, got event from {2}.{3}",
252                eventTracker.DeclaringType.Name,
253                eventTracker.Name,
254                bmt.BoundTo.DeclaringType.Name,
255                bmt.BoundTo.Name));
256        }
257    }
258}