PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Runtime/BinderOps.cs

https://bitbucket.org/stefanrusek/xronos
C# | 357 lines | 262 code | 55 blank | 40 comment | 54 complexity | dd6a1c7c4919d876240197c13ab903c1 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections;
  21. using System.Collections.Generic;
  22. using System.Reflection;
  23. #if CODEPLEX_40
  24. using System.Dynamic;
  25. #else
  26. using Microsoft.Scripting;
  27. #endif
  28. using System.Text;
  29. using Microsoft.Scripting.Actions;
  30. using Microsoft.Scripting.Generation;
  31. using Microsoft.Scripting.Utils;
  32. namespace Microsoft.Scripting.Runtime {
  33. /// <summary>
  34. /// Helper methods that calls are generated to from the default DLR binders.
  35. /// </summary>
  36. public static class BinderOps {
  37. #region CreateDelegate support
  38. /// <summary> Table of dynamicly generated delegates which are shared based upon method signature. </summary>
  39. private static readonly Publisher<DelegateSignatureInfo, DelegateInfo> _dynamicDelegateCache = new Publisher<DelegateSignatureInfo, DelegateInfo>();
  40. public static T CreateDelegate<T>(LanguageContext context, object callable) {
  41. return (T)(object)GetDelegate(context, callable, typeof(T));
  42. }
  43. /// <summary>
  44. /// Creates a delegate with a given signature that could be used to invoke this object from non-dynamic code (w/o code context).
  45. /// A stub is created that makes appropriate conversions/boxing and calls the object.
  46. /// The stub should be executed within a context of this object's language.
  47. /// </summary>
  48. /// <returns>The delegate or a <c>null</c> reference if the object is not callable.</returns>
  49. public static Delegate GetDelegate(LanguageContext context, object callableObject, Type delegateType) {
  50. ContractUtils.RequiresNotNull(context, "context");
  51. ContractUtils.RequiresNotNull(delegateType, "delegateType");
  52. Delegate result = callableObject as Delegate;
  53. if (result != null) {
  54. if (!delegateType.IsAssignableFrom(result.GetType())) {
  55. throw ScriptingRuntimeHelpers.SimpleTypeError(String.Format("Cannot cast {0} to {1}.", result.GetType(), delegateType));
  56. }
  57. return result;
  58. }
  59. IDynamicMetaObjectProvider dynamicObject = callableObject as IDynamicMetaObjectProvider;
  60. if (dynamicObject != null) {
  61. MethodInfo invoke;
  62. if (!typeof(Delegate).IsAssignableFrom(delegateType) || (invoke = delegateType.GetMethod("Invoke")) == null) {
  63. throw ScriptingRuntimeHelpers.SimpleTypeError("A specific delegate type is required.");
  64. }
  65. ParameterInfo[] parameters = invoke.GetParameters();
  66. DelegateSignatureInfo signatureInfo = new DelegateSignatureInfo(
  67. context,
  68. invoke.ReturnType,
  69. parameters
  70. );
  71. DelegateInfo delegateInfo = _dynamicDelegateCache.GetOrCreateValue(signatureInfo,
  72. delegate() {
  73. // creation code
  74. return signatureInfo.GenerateDelegateStub();
  75. });
  76. result = delegateInfo.CreateDelegate(delegateType, dynamicObject);
  77. if (result != null) {
  78. return result;
  79. }
  80. }
  81. throw ScriptingRuntimeHelpers.SimpleTypeError("Object is not callable.");
  82. }
  83. #endregion
  84. /// <summary>
  85. /// Helper function to combine an object array with a sequence of additional parameters that has been splatted for a function call.
  86. /// </summary>
  87. public static object[] GetCombinedParameters(object[] initialArgs, object additionalArgs) {
  88. IList listArgs = additionalArgs as IList;
  89. if (listArgs == null) {
  90. IEnumerable ie = additionalArgs as IEnumerable;
  91. if (ie == null) {
  92. throw new InvalidOperationException("args must be iterable");
  93. }
  94. listArgs = new List<object>();
  95. foreach (object o in ie) {
  96. listArgs.Add(o);
  97. }
  98. }
  99. object[] res = new object[initialArgs.Length + listArgs.Count];
  100. Array.Copy(initialArgs, res, initialArgs.Length);
  101. listArgs.CopyTo(res, initialArgs.Length);
  102. return res;
  103. }
  104. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "2#")] // TODO: fix
  105. public static object[] GetCombinedKeywordParameters(object[] initialArgs, IAttributesCollection additionalArgs, ref string[] extraNames) {
  106. List<object> args = new List<object>(initialArgs);
  107. List<string> newNames = extraNames == null ? new List<string>(additionalArgs.Count) : new List<string>(extraNames);
  108. foreach(KeyValuePair<object, object> kvp in additionalArgs) {
  109. if (kvp.Key is string) {
  110. newNames.Add((string)kvp.Key);
  111. args.Add(kvp.Value);
  112. }
  113. }
  114. extraNames = newNames.ToArray();
  115. return args.ToArray();
  116. }
  117. public static SymbolDictionary MakeSymbolDictionary(string[] names, object[] values) {
  118. SymbolDictionary res = new SymbolDictionary();
  119. for (int i = 0; i < names.Length; i++) {
  120. ((IAttributesCollection)res)[SymbolTable.StringToId(names[i])] = values[i];
  121. }
  122. return res;
  123. }
  124. #region Event support
  125. public static EventTracker EventTrackerInPlaceAdd<T>(CodeContext context, EventTracker self, T target) {
  126. MethodInfo add = self.Event.GetAddMethod(context.LanguageContext.DomainManager.Configuration.PrivateBinding);
  127. add.Invoke(null, new object[] { target });
  128. return self;
  129. }
  130. public static EventTracker EventTrackerInPlaceRemove<T>(CodeContext context, EventTracker self, T target) {
  131. MethodInfo remove = self.Event.GetRemoveMethod(context.LanguageContext.DomainManager.Configuration.PrivateBinding);
  132. remove.Invoke(null, new object[] { target });
  133. return self;
  134. }
  135. public static BoundMemberTracker BoundEventTrackerInPlaceAdd<T>(CodeContext context, BoundMemberTracker self, T target) {
  136. if (self.BoundTo.MemberType == TrackerTypes.Event) {
  137. EventTracker et = (EventTracker)self.BoundTo;
  138. MethodInfo add = et.Event.GetAddMethod(context.LanguageContext.DomainManager.Configuration.PrivateBinding);
  139. add.Invoke(self.ObjectInstance, new object[] { target });
  140. return self;
  141. }
  142. throw new InvalidOperationException();
  143. }
  144. public static BoundMemberTracker BoundEventTrackerInPlaceRemove<T>(CodeContext context, BoundMemberTracker self, T target) {
  145. if (self.BoundTo.MemberType == TrackerTypes.Event) {
  146. EventTracker et = (EventTracker)self.BoundTo;
  147. MethodInfo remove = et.Event.GetRemoveMethod(context.LanguageContext.DomainManager.Configuration.PrivateBinding);
  148. remove.Invoke(self.ObjectInstance, new object[] { target });
  149. return self;
  150. }
  151. throw new InvalidOperationException();
  152. }
  153. #endregion
  154. public static ArgumentTypeException BadArgumentsForOperation(Operators op, params object[] args) {
  155. StringBuilder message = new StringBuilder("unsupported operand type(s) for operation ");
  156. message.Append(op.ToString());
  157. message.Append(": ");
  158. string comma = "";
  159. foreach (object o in args) {
  160. message.Append(comma);
  161. message.Append(CompilerHelpers.GetType(o));
  162. comma = ", ";
  163. }
  164. throw new ArgumentTypeException(message.ToString());
  165. }
  166. // formalNormalArgumentCount - does not include FuncDefFlags.ArgList and FuncDefFlags.KwDict
  167. // defaultArgumentCount - How many arguments in the method declaration have a default value?
  168. // providedArgumentCount - How many arguments are passed in at the call site?
  169. // hasArgList - Is the method declaration of the form "foo(*argList)"?
  170. // keywordArgumentsProvided - Does the call site specify keyword arguments?
  171. public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(
  172. string methodName,
  173. int formalNormalArgumentCount,
  174. int defaultArgumentCount,
  175. int providedArgumentCount,
  176. bool hasArgList,
  177. bool keywordArgumentsProvided) {
  178. return TypeErrorForIncorrectArgumentCount(methodName, formalNormalArgumentCount, formalNormalArgumentCount, defaultArgumentCount, providedArgumentCount, hasArgList, keywordArgumentsProvided);
  179. }
  180. public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(
  181. string methodName,
  182. int minFormalNormalArgumentCount,
  183. int maxFormalNormalArgumentCount,
  184. int defaultArgumentCount,
  185. int providedArgumentCount,
  186. bool hasArgList,
  187. bool keywordArgumentsProvided) {
  188. int formalCount;
  189. string formalCountQualifier;
  190. string nonKeyword = keywordArgumentsProvided ? "non-keyword " : "";
  191. if (defaultArgumentCount > 0 || hasArgList || minFormalNormalArgumentCount != maxFormalNormalArgumentCount) {
  192. if (providedArgumentCount < minFormalNormalArgumentCount || maxFormalNormalArgumentCount == Int32.MaxValue) {
  193. formalCountQualifier = "at least";
  194. formalCount = minFormalNormalArgumentCount - defaultArgumentCount;
  195. } else {
  196. formalCountQualifier = "at most";
  197. formalCount = maxFormalNormalArgumentCount;
  198. }
  199. } else if (minFormalNormalArgumentCount == 0) {
  200. return ScriptingRuntimeHelpers.SimpleTypeError(string.Format("{0}() takes no arguments ({1} given)", methodName, providedArgumentCount));
  201. } else {
  202. formalCountQualifier = "exactly";
  203. formalCount = minFormalNormalArgumentCount;
  204. }
  205. return new ArgumentTypeException(string.Format(
  206. "{0}() takes {1} {2} {3}argument{4} ({5} given)",
  207. methodName, // 0
  208. formalCountQualifier, // 1
  209. formalCount, // 2
  210. nonKeyword, // 3
  211. formalCount == 1 ? "" : "s", // 4
  212. providedArgumentCount)); // 5
  213. }
  214. public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(string name, int formalNormalArgumentCount, int defaultArgumentCount, int providedArgumentCount) {
  215. return TypeErrorForIncorrectArgumentCount(name, formalNormalArgumentCount, defaultArgumentCount, providedArgumentCount, false, false);
  216. }
  217. public static ArgumentTypeException TypeErrorForIncorrectArgumentCount(string name, int expected, int received) {
  218. return TypeErrorForIncorrectArgumentCount(name, expected, 0, received);
  219. }
  220. public static ArgumentTypeException TypeErrorForExtraKeywordArgument(string name, string argumentName) {
  221. return new ArgumentTypeException(String.Format("{0}() got an unexpected keyword argument '{1}'", name, argumentName));
  222. }
  223. public static ArgumentTypeException TypeErrorForDuplicateKeywordArgument(string name, string argumentName) {
  224. return new ArgumentTypeException(String.Format("{0}() got multiple values for keyword argument '{1}'", name, argumentName));
  225. }
  226. public static ArgumentTypeException SimpleTypeError(string message) {
  227. return new ArgumentTypeException(message);
  228. }
  229. public static object InvokeMethod(MethodBase mb, object obj, object[] args) {
  230. try {
  231. return mb.Invoke(obj, args);
  232. } catch (TargetInvocationException tie) {
  233. throw tie.InnerException;
  234. }
  235. }
  236. public static object InvokeConstructor(ConstructorInfo ci, object[] args) {
  237. try {
  238. return ci.Invoke(args);
  239. } catch (TargetInvocationException tie) {
  240. throw tie.InnerException;
  241. }
  242. }
  243. // TODO: just emit this in the generated code
  244. public static bool CheckDictionaryMembers(IDictionary dict, string[] names, Type[] types) {
  245. if (dict.Count != names.Length) return false;
  246. for (int i = 0; i < names.Length; i++) {
  247. string name = names[i];
  248. if (!dict.Contains(name)) {
  249. return false;
  250. }
  251. if (types != null) {
  252. if (CompilerHelpers.GetType(dict[name]) != types[i]) {
  253. return false;
  254. }
  255. }
  256. }
  257. return true;
  258. }
  259. public static IList<string> GetStringMembers(IList<object> members) {
  260. List<string> res = new List<string>();
  261. foreach (object o in members) {
  262. string str = o as string;
  263. if (str != null) {
  264. res.Add(str);
  265. }
  266. }
  267. return res;
  268. }
  269. /// <summary>
  270. /// EventInfo.EventHandlerType getter is marked SecuritySafeCritical in CoreCLR
  271. /// This method is to get to the property without using Reflection
  272. /// </summary>
  273. /// <param name="eventInfo"></param>
  274. /// <returns></returns>
  275. public static Type GetEventHandlerType(EventInfo eventInfo) {
  276. ContractUtils.RequiresNotNull(eventInfo, "eventInfo");
  277. return eventInfo.EventHandlerType;
  278. }
  279. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix
  280. public static void SetEvent(EventTracker eventTracker, object value) {
  281. EventTracker et = value as EventTracker;
  282. if (et != null) {
  283. if (et != eventTracker) {
  284. throw new ArgumentException(String.Format("expected event from {0}.{1}, got event from {2}.{3}",
  285. eventTracker.DeclaringType.Name,
  286. eventTracker.Name,
  287. et.DeclaringType.Name,
  288. et.Name));
  289. }
  290. return;
  291. }
  292. BoundMemberTracker bmt = value as BoundMemberTracker;
  293. if (bmt == null) throw new ArgumentTypeException("expected bound event, got " + CompilerHelpers.GetType(value).Name);
  294. if (bmt.BoundTo.MemberType != TrackerTypes.Event) throw new ArgumentTypeException("expected bound event, got " + bmt.BoundTo.MemberType.ToString());
  295. if (bmt.BoundTo != eventTracker) throw new ArgumentException(String.Format("expected event from {0}.{1}, got event from {2}.{3}",
  296. eventTracker.DeclaringType.Name,
  297. eventTracker.Name,
  298. bmt.BoundTo.DeclaringType.Name,
  299. bmt.BoundTo.Name));
  300. }
  301. }
  302. }