PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Binding/SlotOrFunction.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 347 lines | 265 code | 46 blank | 36 comment | 68 complexity | 8479bca3f4536544104b15e59303421b 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 !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Diagnostics;
  23. using System.Reflection;
  24. using System.Dynamic;
  25. using IronPython.Runtime.Types;
  26. using Microsoft.Scripting;
  27. using Microsoft.Scripting.Actions;
  28. using Microsoft.Scripting.Actions.Calls;
  29. using Microsoft.Scripting.Generation;
  30. using Microsoft.Scripting.Utils;
  31. using Microsoft.Scripting.Runtime;
  32. namespace IronPython.Runtime.Binding {
  33. using Ast = Expression;
  34. using AstUtils = Microsoft.Scripting.Ast.Utils;
  35. /// <summary>
  36. /// Provides an abstraction for calling something which might be a builtin function or
  37. /// might be some arbitrary user defined slot. If the object is a builtin function the
  38. /// call will go directly to the underlying .NET method. If the object is an arbitrary
  39. /// callable object we will setup a nested dynamic site for performing the additional
  40. /// dispatch.
  41. ///
  42. /// TODO: We could probably do a specific binding to the object if it's another IDyanmicObject.
  43. /// </summary>
  44. sealed class SlotOrFunction {
  45. private readonly BindingTarget _function;
  46. private readonly DynamicMetaObject/*!*/ _target;
  47. private readonly PythonTypeSlot _slot;
  48. public static readonly SlotOrFunction/*!*/ Empty = new SlotOrFunction(new DynamicMetaObject(AstUtils.Empty(), BindingRestrictions.Empty));
  49. private SlotOrFunction() {
  50. }
  51. public SlotOrFunction(BindingTarget/*!*/ function, DynamicMetaObject/*!*/ target) {
  52. _target = target;
  53. _function = function;
  54. }
  55. public SlotOrFunction(DynamicMetaObject/*!*/ target) {
  56. _target = target;
  57. }
  58. public SlotOrFunction(DynamicMetaObject/*!*/ target, PythonTypeSlot slot) {
  59. _target = target;
  60. _slot = slot;
  61. }
  62. public NarrowingLevel NarrowingLevel {
  63. get {
  64. if (_function != null) {
  65. return _function.NarrowingLevel;
  66. }
  67. return NarrowingLevel.None;
  68. }
  69. }
  70. public Type/*!*/ ReturnType {
  71. get {
  72. return _target.GetLimitType();
  73. }
  74. }
  75. public bool MaybeNotImplemented {
  76. get {
  77. if (_function != null) {
  78. ParameterInfo ret = _function.Overload.ReturnParameter;
  79. return ret != null && ret.IsDefined(typeof(MaybeNotImplementedAttribute), false);
  80. }
  81. return true;
  82. }
  83. }
  84. public bool Success {
  85. get {
  86. if (_function != null) {
  87. return _function.Success;
  88. }
  89. return this != Empty;
  90. }
  91. }
  92. public bool IsNull {
  93. get {
  94. if (_slot is PythonTypeUserDescriptorSlot && ((PythonTypeUserDescriptorSlot)_slot).Value == null) {
  95. return true;
  96. }
  97. return false;
  98. }
  99. }
  100. public DynamicMetaObject/*!*/ Target {
  101. get {
  102. return _target;
  103. }
  104. }
  105. /// <summary>
  106. /// Combines two methods, which came from two different binary types, selecting the method which has the best
  107. /// set of conversions (the conversions which result in the least narrowing).
  108. /// </summary>
  109. public static bool GetCombinedTargets(SlotOrFunction fCand, SlotOrFunction rCand, out SlotOrFunction fTarget, out SlotOrFunction rTarget) {
  110. fTarget = rTarget = Empty;
  111. if (fCand.Success) {
  112. if (rCand.Success) {
  113. if (fCand.NarrowingLevel <= rCand.NarrowingLevel) {
  114. fTarget = fCand;
  115. rTarget = rCand;
  116. } else {
  117. fTarget = Empty;
  118. rTarget = rCand;
  119. }
  120. } else {
  121. fTarget = fCand;
  122. }
  123. } else if (rCand.Success) {
  124. rTarget = rCand;
  125. } else {
  126. return false;
  127. }
  128. return true;
  129. }
  130. public bool ShouldWarn(PythonContext context, out WarningInfo info) {
  131. if (_function != null) {
  132. return BindingWarnings.ShouldWarn(context, _function.Overload, out info);
  133. }
  134. info = null;
  135. return false;
  136. }
  137. public static SlotOrFunction/*!*/ GetSlotOrFunction(PythonContext/*!*/ state, string op, params DynamicMetaObject[] types) {
  138. PythonTypeSlot slot;
  139. SlotOrFunction res;
  140. if (TryGetBinder(state, types, op, null, out res)) {
  141. if (res != SlotOrFunction.Empty) {
  142. return res;
  143. }
  144. } else if (MetaUserObject.GetPythonType(types[0]).TryResolveSlot(state.SharedContext, op, out slot)) {
  145. ParameterExpression tmp = Ast.Variable(typeof(object), "slotVal");
  146. Expression[] args = new Expression[types.Length - 1];
  147. for (int i = 1; i < types.Length; i++) {
  148. args[i - 1] = types[i].Expression;
  149. }
  150. return new SlotOrFunction(
  151. new DynamicMetaObject(
  152. Ast.Block(
  153. new ParameterExpression[] { tmp },
  154. MetaPythonObject.MakeTryGetTypeMember(
  155. state,
  156. slot,
  157. tmp,
  158. types[0].Expression,
  159. Ast.Call(
  160. typeof(DynamicHelpers).GetMethod("GetPythonType"),
  161. types[0].Expression
  162. )
  163. ),
  164. Ast.Dynamic(
  165. state.Invoke(
  166. new CallSignature(args.Length)
  167. ),
  168. typeof(object),
  169. ArrayUtils.Insert<Expression>(
  170. AstUtils.Constant(state.SharedContext),
  171. tmp,
  172. args
  173. )
  174. )
  175. ),
  176. BindingRestrictions.Combine(types).Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(types[0].Expression, types[0].GetLimitType()))
  177. ),
  178. slot
  179. );
  180. }
  181. return SlotOrFunction.Empty;
  182. }
  183. internal static bool TryGetBinder(PythonContext/*!*/ state, DynamicMetaObject/*!*/[]/*!*/ types, string op, string rop, out SlotOrFunction/*!*/ res) {
  184. PythonType declType;
  185. return TryGetBinder(state, types, op, rop, out res, out declType);
  186. }
  187. /// <summary>
  188. /// Tries to get a MethodBinder associated with the slot for the specified type.
  189. ///
  190. /// If a method is found the binder is set and true is returned.
  191. /// If nothing is found binder is null and true is returned.
  192. /// If something other than a method is found false is returned.
  193. ///
  194. /// TODO: Remove rop
  195. /// </summary>
  196. internal static bool TryGetBinder(PythonContext/*!*/ state, DynamicMetaObject/*!*/[]/*!*/ types, string op, string rop, out SlotOrFunction/*!*/ res, out PythonType declaringType) {
  197. declaringType = null;
  198. DynamicMetaObject xType = types[0];
  199. BuiltinFunction xBf;
  200. if (!BindingHelpers.TryGetStaticFunction(state, op, xType, out xBf)) {
  201. res = SlotOrFunction.Empty;
  202. return false;
  203. }
  204. xBf = CheckAlwaysNotImplemented(xBf);
  205. BindingTarget bt;
  206. DynamicMetaObject binder;
  207. DynamicMetaObject yType = null;
  208. BuiltinFunction yBf = null;
  209. if (types.Length > 1) {
  210. yType = types[1];
  211. if (!BindingHelpers.IsSubclassOf(xType, yType) && !BindingHelpers.TryGetStaticFunction(state, rop, yType, out yBf)) {
  212. res = SlotOrFunction.Empty;
  213. return false;
  214. }
  215. yBf = CheckAlwaysNotImplemented(yBf);
  216. }
  217. if (yBf == xBf) {
  218. yBf = null;
  219. } else if (yBf != null && BindingHelpers.IsSubclassOf(yType, xType)) {
  220. xBf = null;
  221. }
  222. var mc = new PythonOverloadResolver(
  223. state.Binder,
  224. types,
  225. new CallSignature(types.Length),
  226. AstUtils.Constant(state.SharedContext)
  227. );
  228. if (xBf == null) {
  229. if (yBf == null) {
  230. binder = null;
  231. bt = null;
  232. } else {
  233. declaringType = DynamicHelpers.GetPythonTypeFromType(yBf.DeclaringType);
  234. binder = state.Binder.CallMethod(mc, yBf.Targets, BindingRestrictions.Empty, null, PythonNarrowing.None, PythonNarrowing.BinaryOperator, out bt);
  235. }
  236. } else {
  237. if (yBf == null) {
  238. declaringType = DynamicHelpers.GetPythonTypeFromType(xBf.DeclaringType);
  239. binder = state.Binder.CallMethod(mc, xBf.Targets, BindingRestrictions.Empty, null, PythonNarrowing.None, PythonNarrowing.BinaryOperator, out bt);
  240. } else {
  241. List<MethodBase> targets = new List<MethodBase>();
  242. targets.AddRange(xBf.Targets);
  243. foreach (MethodBase mb in yBf.Targets) {
  244. if (!ContainsMethodSignature(targets, mb)) targets.Add(mb);
  245. }
  246. binder = state.Binder.CallMethod(mc, targets.ToArray(), BindingRestrictions.Empty, null, PythonNarrowing.None, PythonNarrowing.BinaryOperator, out bt);
  247. foreach (MethodBase mb in yBf.Targets) {
  248. if (bt.Overload.ReflectionInfo == mb) {
  249. declaringType = DynamicHelpers.GetPythonTypeFromType(yBf.DeclaringType);
  250. break;
  251. }
  252. }
  253. if (declaringType == null) {
  254. declaringType = DynamicHelpers.GetPythonTypeFromType(xBf.DeclaringType);
  255. }
  256. }
  257. }
  258. if (binder != null) {
  259. res = new SlotOrFunction(bt, binder);
  260. } else {
  261. res = SlotOrFunction.Empty;
  262. }
  263. Debug.Assert(res != null);
  264. return true;
  265. }
  266. private static BuiltinFunction CheckAlwaysNotImplemented(BuiltinFunction xBf) {
  267. if (xBf != null) {
  268. bool returnsValue = false;
  269. foreach (MethodBase mb in xBf.Targets) {
  270. if (mb.GetReturnType() != typeof(NotImplementedType) ||
  271. mb.IsDefined(typeof(Python3WarningAttribute), true)) {
  272. returnsValue = true;
  273. break;
  274. }
  275. }
  276. if (!returnsValue) {
  277. xBf = null;
  278. }
  279. }
  280. return xBf;
  281. }
  282. private static bool ContainsMethodSignature(IList<MethodBase/*!*/>/*!*/ existing, MethodBase/*!*/ check) {
  283. ParameterInfo[] pis = check.GetParameters();
  284. foreach (MethodBase mb in existing) {
  285. if (MatchesMethodSignature(pis, mb)) return true;
  286. }
  287. return false;
  288. }
  289. private static bool MatchesMethodSignature(ParameterInfo/*!*/[]/*!*/ pis, MethodBase/*!*/ mb) {
  290. ParameterInfo[] pis1 = mb.GetParameters();
  291. if (pis.Length == pis1.Length) {
  292. for (int i = 0; i < pis.Length; i++) {
  293. if (pis[i].ParameterType != pis1[i].ParameterType) return false;
  294. }
  295. return true;
  296. } else {
  297. return false;
  298. }
  299. }
  300. }
  301. }