PageRenderTime 55ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/DICK.B1/IronPython/Runtime/Types/TypeInfo.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 2086 lines | 1424 code | 311 blank | 351 comment | 479 complexity | 7dafa1e41cc2f69ca71e4c7ae768420c 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. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Reflection;
  20. using System.Dynamic;
  21. using System.Threading;
  22. using Microsoft.Scripting;
  23. using Microsoft.Scripting.Actions;
  24. using Microsoft.Scripting.Generation;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime.Binding;
  28. using IronPython.Runtime.Exceptions;
  29. using IronPython.Runtime.Operations;
  30. #if CLR2
  31. using Microsoft.Scripting.Math;
  32. using Complex = Microsoft.Scripting.Math.Complex64;
  33. #else
  34. using System.Numerics;
  35. #endif
  36. namespace IronPython.Runtime.Types {
  37. /// <summary>
  38. /// Helpers for interacting w/ .NET types. This includes:
  39. ///
  40. /// Member resolution via GetMember/GetMembers. This performs a member lookup which includes the registered
  41. /// extension types in the PythonBinder. Internally the class has many MemberResolver's which provide
  42. /// the various resolution behaviors.
  43. ///
  44. /// Cached member access - this is via static classes such as Object and provides various MemberInfo's so we're
  45. /// not constantly looking up via reflection.
  46. /// </summary>
  47. internal static partial class TypeInfo {
  48. /// <summary> list of resolvers which we run to resolve items </summary>
  49. private static readonly MemberResolver/*!*/[]/*!*/ _resolvers = MakeResolverTable();
  50. [MultiRuntimeAware]
  51. private static DocumentationDescriptor _docDescr;
  52. [MultiRuntimeAware]
  53. internal static Dictionary<string, PythonOperationKind> _pythonOperatorTable;
  54. #region Public member resolution
  55. /// <summary>
  56. /// Gets the statically known member from the type with the specific name. Searches the entire type hierarchy to find the specified member.
  57. /// </summary>
  58. public static MemberGroup/*!*/ GetMemberAll(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  59. Assert.NotNull(binder, action, type, name);
  60. PerfTrack.NoteEvent(PerfTrack.Categories.ReflectedTypes, String.Format("ResolveMember: {0} {1}", type.Name, name));
  61. return GetMemberGroup(new ResolveBinder(binder), action, type, name);
  62. }
  63. /// <summary>
  64. /// Gets all the statically known members from the specified type. Searches the entire type hierarchy to get all possible members.
  65. ///
  66. /// The result may include multiple resolution. It is the callers responsibility to only treat the 1st one by name as existing.
  67. /// </summary>
  68. public static IList<ResolvedMember/*!*/>/*!*/ GetMembersAll(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  69. Assert.NotNull(binder, action, type);
  70. return GetResolvedMembers(new ResolveBinder(binder), action, type);
  71. }
  72. /// <summary>
  73. /// Gets the statically known member from the type with the specific name. Searches only the specified type to find the member.
  74. /// </summary>
  75. public static MemberGroup/*!*/ GetMember(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  76. Assert.NotNull(binder, action, type, name);
  77. PerfTrack.NoteEvent(PerfTrack.Categories.ReflectedTypes, String.Format("LookupMember: {0} {1}", type.Name, name));
  78. return GetMemberGroup(new LookupBinder(binder), action, type, name);
  79. }
  80. /// <summary>
  81. /// Gets all the statically known members from the specified type. Searches only the specified type to find the members.
  82. ///
  83. /// The result may include multiple resolution. It is the callers responsibility to only treat the 1st one by name as existing.
  84. /// </summary>
  85. public static IList<ResolvedMember/*!*/>/*!*/ GetMembers(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  86. Assert.NotNull(binder, action, type);
  87. return GetResolvedMembers(new LookupBinder(binder), action, type);
  88. }
  89. #endregion
  90. #region Cached type members
  91. public static class _Object {
  92. public new static readonly MethodInfo/*!*/ GetType = typeof(object).GetMethod("GetType");
  93. }
  94. public static class _IPythonObject {
  95. public static readonly PropertyInfo/*!*/ PythonType = typeof(IPythonObject).GetProperty("PythonType");
  96. public static readonly PropertyInfo/*!*/ Dict = typeof(IPythonObject).GetProperty("Dict");
  97. }
  98. public static class _PythonOps {
  99. public static readonly MethodInfo/*!*/ SlotTryGetBoundValue = typeof(PythonOps).GetMethod("SlotTryGetBoundValue");
  100. public static readonly MethodInfo/*!*/ GetTypeVersion = typeof(PythonOps).GetMethod("GetTypeVersion");
  101. public static readonly MethodInfo/*!*/ CheckTypeVersion = typeof(PythonOps).GetMethod("CheckTypeVersion");
  102. }
  103. public static class _OperationFailed {
  104. public static readonly FieldInfo/*!*/ Value = typeof(OperationFailed).GetField("Value");
  105. }
  106. public static class _PythonDictionary {
  107. public static readonly MethodInfo/*!*/ TryGetvalue = typeof(PythonDictionary).GetMethod("TryGetValue");
  108. }
  109. public static class _PythonGenerator {
  110. public static readonly ConstructorInfo Ctor = typeof(PythonGenerator).GetConstructor(new Type[] { typeof(PythonFunction) });
  111. }
  112. #endregion
  113. #region MemberResolver implementations and infrastructure
  114. /// <summary>
  115. /// Abstract class used for resolving members. This provides two methods of member look. The first is looking
  116. /// up a single member by name. The other is getting all of the members.
  117. ///
  118. /// There are various subclasses of this which have different methods of resolving the members. The primary
  119. /// function of the resolvers are to provide the name->value lookup. They also need to provide a simple name
  120. /// enumerator. The enumerator is kept simple because it's allowed to return duplicate names as well as return
  121. /// names of members that don't exist. The base MemberResolver will then verify their existance as well as
  122. /// filter duplicates.
  123. /// </summary>
  124. abstract class MemberResolver {
  125. /// <summary>
  126. /// Looks up an individual member and returns a MemberGroup with the given members.
  127. /// </summary>
  128. public abstract MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name);
  129. /// <summary>
  130. /// Returns a list of members that exist on the type. The ResolvedMember structure indicates both
  131. /// the name and provides the MemberGroup.
  132. /// </summary>
  133. public IList<ResolvedMember/*!*/>/*!*/ ResolveMembers(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  134. Dictionary<string, ResolvedMember> members = new Dictionary<string, ResolvedMember>();
  135. foreach (string name in GetCandidateNames(binder, action, type)) {
  136. if (members.ContainsKey(name)) {
  137. continue;
  138. }
  139. MemberGroup member = ResolveMember(binder, action, type, name);
  140. if (member.Count > 0) {
  141. members[name] = new ResolvedMember(name, member);
  142. }
  143. }
  144. ResolvedMember[] res = new ResolvedMember[members.Count];
  145. members.Values.CopyTo(res, 0);
  146. return res;
  147. }
  148. /// <summary>
  149. /// Returns a list of possible members which could exist. ResolveMember needs to be called to verify their existance. Duplicate
  150. /// names can also be returned.
  151. /// </summary>
  152. protected abstract IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type);
  153. }
  154. /// <summary>
  155. /// One off resolver for various special methods which are known by name. A delegate is provided to provide the actual member which
  156. /// will be resolved.
  157. /// </summary>
  158. class OneOffResolver : MemberResolver {
  159. private string/*!*/ _name;
  160. private Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ _resolver;
  161. public OneOffResolver(string/*!*/ name, Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ resolver) {
  162. Assert.NotNull(name, resolver);
  163. _name = name;
  164. _resolver = resolver;
  165. }
  166. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  167. Assert.NotNull(binder, action, type, name);
  168. if (name == _name) {
  169. return _resolver(binder, type);
  170. }
  171. return MemberGroup.EmptyGroup;
  172. }
  173. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  174. yield return _name;
  175. }
  176. }
  177. /// <summary>
  178. /// Standard resolver for looking up .NET members. Uses reflection to get the members by name.
  179. /// </summary>
  180. class StandardResolver : MemberResolver {
  181. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  182. if (name == ".ctor" || name == ".cctor") return MemberGroup.EmptyGroup;
  183. // normal binding
  184. MemberGroup res;
  185. foreach (Type curType in binder.GetContributingTypes(type)) {
  186. res = FilterSpecialNames(binder.GetMember(curType, name), name, action);
  187. if (res.Count > 0) {
  188. return res;
  189. }
  190. }
  191. if (type.IsInterface) {
  192. foreach (Type t in type.GetInterfaces()) {
  193. res = FilterSpecialNames(binder.GetMember(t, name), name, action);
  194. if (res.Count > 0) {
  195. return res;
  196. }
  197. }
  198. }
  199. return MemberGroup.EmptyGroup;
  200. }
  201. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  202. foreach (Type curType in binder.GetContributingTypes(type)) {
  203. foreach (MemberInfo mi in curType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
  204. if (mi.MemberType == MemberTypes.Method) {
  205. MethodInfo meth = (MethodInfo)mi;
  206. if (meth.IsSpecialName) {
  207. if (meth.IsDefined(typeof(PropertyMethodAttribute), true)) {
  208. if (meth.Name.StartsWith("Get") || meth.Name.StartsWith("Set")) {
  209. yield return meth.Name.Substring(3);
  210. } else {
  211. Debug.Assert(meth.Name.StartsWith("Delete"));
  212. yield return meth.Name.Substring(6);
  213. }
  214. }
  215. continue;
  216. }
  217. }
  218. yield return mi.Name;
  219. }
  220. }
  221. }
  222. }
  223. /// <summary>
  224. /// Resolves methods mapped to __eq__ and __ne__ from:
  225. /// 1. IStructuralEquatable.Equals
  226. /// 2. IValueEquality.Equals (CLR2 only)
  227. /// </summary>
  228. class EqualityResolver : MemberResolver {
  229. public static readonly EqualityResolver Instance = new EqualityResolver();
  230. private EqualityResolver() { }
  231. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  232. Assert.NotNull(binder, action, type, name);
  233. bool equality;
  234. switch (name) {
  235. case "__eq__": equality = true; break;
  236. case "__ne__": equality = false; break;
  237. default:
  238. return MemberGroup.EmptyGroup;
  239. }
  240. if (typeof(IStructuralEquatable).IsAssignableFrom(type)) {
  241. return new MemberGroup(
  242. GetEqualityMethods(type, equality ? "StructuralEqualityMethod" : "StructuralInequalityMethod")
  243. );
  244. #if CLR2
  245. } else if (typeof(IValueEquality).IsAssignableFrom(type)) {
  246. return new MemberGroup(
  247. GetEqualityMethods(type, equality ? "ValueEqualsMethod" : "ValueNotEqualsMethod")
  248. );
  249. #endif
  250. }
  251. return MemberGroup.EmptyGroup;
  252. }
  253. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  254. yield return "__eq__";
  255. yield return "__ne__";
  256. }
  257. }
  258. /// <summary>
  259. /// Resolves methods mapped to __gt__, __lt__, __ge__, __le__, as well as providing an alternate resolution
  260. /// for __eq__ and __ne__, from the comparable type's CompareTo method.
  261. ///
  262. /// This should be run after the EqualityResolver.
  263. /// </summary>
  264. class ComparisonResolver : MemberResolver {
  265. private readonly bool _excludePrimitiveTypes;
  266. private readonly Type/*!*/ _comparable;
  267. private readonly Dictionary<string/*!*/, string/*!*/>/*!*/ _helperMap;
  268. public ComparisonResolver(Type/*!*/ comparable, string/*!*/ helperPrefix) {
  269. Assert.NotNull(comparable, helperPrefix);
  270. _excludePrimitiveTypes = comparable == typeof(IComparable);
  271. _comparable = comparable;
  272. _helperMap = new Dictionary<string, string>();
  273. _helperMap["__eq__"] = helperPrefix + "Equality";
  274. _helperMap["__ne__"] = helperPrefix + "Inequality";
  275. _helperMap["__gt__"] = helperPrefix + "GreaterThan";
  276. _helperMap["__lt__"] = helperPrefix + "LessThan";
  277. _helperMap["__ge__"] = helperPrefix + "GreaterEqual";
  278. _helperMap["__le__"] = helperPrefix + "LessEqual";
  279. }
  280. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  281. Assert.NotNull(binder, action, type, name);
  282. // Do not map IComparable if this is a primitive builtin type.
  283. if (_excludePrimitiveTypes) {
  284. if (type.IsPrimitive || type == typeof(BigInteger) ||
  285. type == typeof(string) || type == typeof(decimal)) {
  286. return MemberGroup.EmptyGroup;
  287. }
  288. }
  289. string helperName;
  290. if (_helperMap.TryGetValue(name, out helperName) &&
  291. _comparable.IsAssignableFrom(type)) {
  292. return new MemberGroup(GetEqualityMethods(type, helperName));
  293. }
  294. return MemberGroup.EmptyGroup;
  295. }
  296. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  297. return _helperMap.Keys;
  298. }
  299. }
  300. /// <summary>
  301. /// Resolves methods mapped to __*__ methods automatically from the .NET operator.
  302. /// </summary>
  303. class OperatorResolver : MemberResolver {
  304. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  305. if (type.IsSealed && type.IsAbstract) {
  306. // static types don't have PythonOperationKind
  307. return MemberGroup.EmptyGroup;
  308. }
  309. // try mapping __*__ methods to .NET method names
  310. PythonOperationKind opMap;
  311. EnsureOperatorTable();
  312. if (_pythonOperatorTable.TryGetValue(name, out opMap)) {
  313. if (IncludeOperatorMethod(type, opMap)) {
  314. OperatorMapping opInfo;
  315. if (IsReverseOperator(opMap)) {
  316. opInfo = OperatorMapping.GetOperatorMapping(opMap & ~PythonOperationKind.Reversed);
  317. } else {
  318. opInfo = OperatorMapping.GetOperatorMapping(opMap);
  319. }
  320. if (opInfo != null) {
  321. foreach (Type curType in binder.GetContributingTypes(type)) {
  322. #if !CLR2
  323. if (curType == typeof(double)) {
  324. if ((opInfo.Operator & PythonOperationKind.Comparison) != 0) {
  325. // we override these with our own comparisons in DoubleOps
  326. continue;
  327. }
  328. } else
  329. #endif
  330. if (curType == typeof(BigInteger)) {
  331. if (opInfo.Operator == PythonOperationKind.Mod ||
  332. opInfo.Operator == PythonOperationKind.RightShift ||
  333. opInfo.Operator == PythonOperationKind.LeftShift ||
  334. opInfo.Operator == PythonOperationKind.Compare ||
  335. opInfo.Operator == PythonOperationKind.Divide) {
  336. // we override these with our own modulus/power PythonOperationKind which are different from BigInteger.
  337. continue;
  338. }
  339. #if !CLR2
  340. } else if (curType == typeof(Complex) && opInfo.Operator == PythonOperationKind.Divide) {
  341. // we override this with our own division PythonOperationKind which is different from .NET Complex.
  342. continue;
  343. #endif
  344. }
  345. Debug.Assert(opInfo.Name != "Equals");
  346. MemberGroup res = binder.GetMember(curType, opInfo.Name);
  347. if (res.Count == 0 && opInfo.AlternateName != null) {
  348. res = binder.GetMember(curType, opInfo.AlternateName);
  349. if (opInfo.AlternateName == "Equals") {
  350. // "Equals" is available as an alternate method name. Because it's also on object and Python
  351. // doesn't define it on object we need to filter it out.
  352. res = FilterObjectEquality(res);
  353. }
  354. res = FilterAlternateMethods(opInfo, res);
  355. }
  356. if (res.Count > 0) {
  357. return FilterForwardReverseMethods(name, res, type, opMap);
  358. }
  359. }
  360. }
  361. }
  362. }
  363. if (name == "__call__") {
  364. MemberGroup res = binder.GetMember(type, "Call");
  365. if (res.Count > 0) {
  366. return res;
  367. }
  368. }
  369. return MemberGroup.EmptyGroup;
  370. }
  371. /// <summary>
  372. /// Filters alternative methods out that don't match the expected signature and therefore
  373. /// are just sharing a common method name.
  374. /// </summary>
  375. private static MemberGroup FilterAlternateMethods(OperatorMapping opInfo, MemberGroup res) {
  376. if (res.Count > 0 && opInfo.AlternateExpectedType != null) {
  377. List<MemberTracker> matchingMethods = new List<MemberTracker>();
  378. for (int i = 0; i < res.Count; i++) {
  379. MemberTracker mt = res[i];
  380. if (mt.MemberType == TrackerTypes.Method &&
  381. ((MethodTracker)mt).Method.ReturnType == opInfo.AlternateExpectedType) {
  382. matchingMethods.Add(mt);
  383. }
  384. }
  385. if (matchingMethods.Count == 0) {
  386. res = MemberGroup.EmptyGroup;
  387. } else {
  388. res = new MemberGroup(matchingMethods.ToArray());
  389. }
  390. }
  391. return res;
  392. }
  393. /// <summary>
  394. /// Removes Object.Equals methods as we never return these for PythonOperationKind.
  395. /// </summary>
  396. private static MemberGroup/*!*/ FilterObjectEquality(MemberGroup/*!*/ group) {
  397. List<MemberTracker> res = null;
  398. for (int i = 0; i < group.Count; i++) {
  399. MemberTracker mt = group[i];
  400. if (mt.MemberType == TrackerTypes.Method && (mt.DeclaringType == typeof(object) || mt.DeclaringType == typeof(double) || mt.DeclaringType == typeof(float)) && mt.Name == "Equals") {
  401. if (res == null) {
  402. res = new List<MemberTracker>();
  403. for (int j = 0; j < i; j++) {
  404. res.Add(group[j]);
  405. }
  406. }
  407. } else if (mt.MemberType == TrackerTypes.Method && mt.DeclaringType == typeof(ValueType) && mt.Name == "Equals") {
  408. // ValueType.Equals overrides object.Equals but we can't call it w/ a boxed value type therefore
  409. // we return the object version and the virtual call will dispatch to ValueType.Equals.
  410. if (res == null) {
  411. res = new List<MemberTracker>();
  412. for (int j = 0; j < i; j++) {
  413. res.Add(group[j]);
  414. }
  415. }
  416. res.Add(MemberTracker.FromMemberInfo(typeof(object).GetMethod("Equals", new Type[] { typeof(object) })));
  417. } else if (res != null) {
  418. res.Add(group[i]);
  419. }
  420. }
  421. if (res != null) {
  422. if (res.Count == 0) {
  423. return MemberGroup.EmptyGroup;
  424. }
  425. return new MemberGroup(res.ToArray());
  426. }
  427. return group;
  428. }
  429. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  430. EnsureOperatorTable();
  431. foreach (string si in _pythonOperatorTable.Keys) {
  432. yield return si;
  433. }
  434. yield return "__call__";
  435. }
  436. }
  437. /// <summary>
  438. /// Provides bindings to private members when that global option is enabled.
  439. /// </summary>
  440. class PrivateBindingResolver : MemberResolver {
  441. private const BindingFlags _privateFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
  442. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  443. if (binder.DomainManager.Configuration.PrivateBinding) {
  444. // in private binding mode Python exposes private members under a mangled name.
  445. string header = "_" + type.Name + "__";
  446. if (name.StartsWith(header)) {
  447. string memberName = name.Substring(header.Length);
  448. MemberGroup res = new MemberGroup(type.GetMember(memberName, _privateFlags));
  449. if (res.Count > 0) {
  450. return FilterFieldAndEvent(res);
  451. }
  452. res = new MemberGroup(type.GetMember(memberName, BindingFlags.FlattenHierarchy | _privateFlags));
  453. if (res.Count > 0) {
  454. return FilterFieldAndEvent(res);
  455. }
  456. }
  457. }
  458. return MemberGroup.EmptyGroup;
  459. }
  460. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  461. if (!binder.DomainManager.Configuration.PrivateBinding) {
  462. yield break;
  463. }
  464. foreach (MemberInfo mi in type.GetMembers(_privateFlags | BindingFlags.FlattenHierarchy)) {
  465. yield return String.Concat("_", mi.DeclaringType.Name, "__", mi.Name);
  466. }
  467. }
  468. }
  469. /// <summary>
  470. /// Provides resolutions for protected members that haven't yet been
  471. /// subclassed by NewTypeMaker.
  472. /// </summary>
  473. class ProtectedMemberResolver : MemberResolver {
  474. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  475. foreach (Type t in binder.GetContributingTypes(type)) {
  476. MemberGroup res = new MemberGroup(ArrayUtils.FindAll(t.GetMember(name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy), ProtectedOnly));
  477. for (int i = 0; i < res.Count; i++) {
  478. MethodTracker meth = res[i] as MethodTracker;
  479. if (meth == null) {
  480. continue;
  481. }
  482. if (meth.Name == "Finalize" && meth.Method.GetBaseDefinition() == typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)) {
  483. MemberTracker[] retained = new MemberTracker[res.Count - 1];
  484. if (res.Count == 1) {
  485. res = MemberGroup.EmptyGroup;
  486. } else {
  487. for (int j = 0; j < i; j++) {
  488. retained[j] = res[j];
  489. }
  490. for (int j = i + 1; j < res.Count; j++) {
  491. retained[j - 1] = res[j];
  492. }
  493. res = new MemberGroup(retained);
  494. }
  495. break;
  496. }
  497. }
  498. return FilterSpecialNames(res, name, action);
  499. }
  500. return MemberGroup.EmptyGroup;
  501. }
  502. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  503. // these members are visible but only accept derived types.
  504. foreach (Type t in binder.GetContributingTypes(type)) {
  505. MemberInfo[] mems = ArrayUtils.FindAll(t.GetMembers(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic), ProtectedOnly);
  506. foreach (MemberInfo mi in mems) {
  507. yield return mi.Name;
  508. }
  509. }
  510. }
  511. }
  512. /// <summary>
  513. /// Creates the resolver table which includes all the possible resolutions.
  514. /// </summary>
  515. /// <returns></returns>
  516. private static MemberResolver/*!*/[]/*!*/ MakeResolverTable() {
  517. return new MemberResolver[] {
  518. // values that live on object need to run before the StandardResolver
  519. // which will pick up values off of object.
  520. new OneOffResolver("__str__", StringResolver),
  521. new OneOffResolver("__new__", NewResolver),
  522. new OneOffResolver("__repr__", ReprResolver),
  523. new OneOffResolver("__hash__", HashResolver),
  524. new OneOffResolver("__iter__", IterResolver),
  525. #if !SILVERLIGHT
  526. new OneOffResolver("__reduce_ex__", SerializationResolver),
  527. #endif
  528. // The standard resolver looks for types using .NET reflection by name
  529. new StandardResolver(),
  530. // Runs after StandardResolver so custom __eq__ methods can be added
  531. // that support things like returning NotImplemented vs. IValueEquality
  532. // which only supports true/false. Runs before OperatorResolver so that
  533. // IStructuralEquatable and IValueEquality take precedence over Equals,
  534. // which can be provided for nice .NET interop.
  535. EqualityResolver.Instance,
  536. new ComparisonResolver(typeof(IStructuralComparable), "StructuralComparable"),
  537. new OneOffResolver("__all__", AllResolver),
  538. new OneOffResolver("__contains__", ContainsResolver),
  539. new OneOffResolver("__dir__", DirResolver),
  540. new OneOffResolver("__doc__", DocResolver),
  541. new OneOffResolver("__enter__", EnterResolver),
  542. new OneOffResolver("__exit__", ExitResolver),
  543. new OneOffResolver("__len__", LengthResolver),
  544. new OneOffResolver("__format__", FormatResolver),
  545. new OneOffResolver("next", NextResolver),
  546. new OneOffResolver("__complex__", ComplexResolver),
  547. new OneOffResolver("__float__", FloatResolver),
  548. new OneOffResolver("__int__", IntResolver),
  549. new OneOffResolver("__long__", BigIntegerResolver),
  550. // non standard PythonOperationKind which are Python specific
  551. new OneOffResolver("__truediv__", new OneOffOperatorBinder("TrueDivide", "__truediv__", PythonOperationKind.TrueDivide).Resolver),
  552. new OneOffResolver("__rtruediv__", new OneOffOperatorBinder("TrueDivide", "__rtruediv__", PythonOperationKind.ReverseTrueDivide).Resolver),
  553. new OneOffResolver("__itruediv__", new OneOffOperatorBinder("InPlaceTrueDivide", "__itruediv__", PythonOperationKind.InPlaceTrueDivide).Resolver),
  554. new OneOffResolver("__floordiv__", new OneOffOperatorBinder("FloorDivide", "__floordiv__", PythonOperationKind.FloorDivide).Resolver),
  555. new OneOffResolver("__rfloordiv__", new OneOffOperatorBinder("FloorDivide", "__rfloordiv__", PythonOperationKind.ReverseFloorDivide).Resolver),
  556. new OneOffResolver("__ifloordiv__", new OneOffOperatorBinder("InPlaceFloorDivide", "__ifloordiv__", PythonOperationKind.InPlaceFloorDivide).Resolver),
  557. new OneOffResolver("__pow__", new OneOffPowerBinder("__pow__", PythonOperationKind.Power).Resolver),
  558. new OneOffResolver("__rpow__", new OneOffPowerBinder("__rpow__", PythonOperationKind.ReversePower).Resolver),
  559. new OneOffResolver("__ipow__", new OneOffOperatorBinder("InPlacePower", "__ipow__", PythonOperationKind.InPlacePower).Resolver),
  560. new OneOffResolver("__abs__", new OneOffOperatorBinder("Abs", "__abs__", PythonOperationKind.AbsoluteValue).Resolver),
  561. new OneOffResolver("__divmod__", new OneOffOperatorBinder("DivMod", "__divmod__", PythonOperationKind.DivMod).Resolver),
  562. new OneOffResolver("__rdivmod__", new OneOffOperatorBinder("DivMod", "__rdivmod__", PythonOperationKind.DivMod).Resolver),
  563. // The operator resolver maps standard .NET operator methods into Python operator
  564. // methods
  565. new OperatorResolver(),
  566. // Runs after operator resolver to map default members to __getitem__/__setitem__
  567. new OneOffResolver("__getitem__", GetItemResolver),
  568. new OneOffResolver("__setitem__", SetItemResolver),
  569. // Runs after operator resolver to map __ne__ -> !__eq__
  570. new OneOffResolver("__ne__", FallbackInequalityResolver),
  571. // Runs after the operator resolver to map IComparable
  572. new ComparisonResolver(typeof(IComparable), "Comparable"),
  573. // Protected members are visible but only usable from derived types
  574. new ProtectedMemberResolver(),
  575. // Support binding to private members if the user has enabled that feature
  576. new PrivateBindingResolver(),
  577. };
  578. }
  579. #endregion
  580. #region One-off resolvers
  581. #region Resolving numerical conversions (__complex__, __float__, __int__, and __long__)
  582. /// <summary>
  583. /// Provides a resolution for __complex__
  584. /// </summary>
  585. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ ComplexResolver {
  586. get {
  587. if (_ComplexResolver != null) return _ComplexResolver;
  588. _ComplexResolver = MakeConversionResolver(new List<Type> {
  589. typeof(Complex), typeof(ExtensibleComplex), typeof(Extensible<Complex>),
  590. typeof(double), typeof(Extensible<double>)
  591. });
  592. return _ComplexResolver;
  593. }
  594. }
  595. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _ComplexResolver;
  596. /// <summary>
  597. /// Provides a resolution for __float__
  598. /// </summary>
  599. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ FloatResolver {
  600. get {
  601. if (_FloatResolver != null) return _FloatResolver;
  602. _FloatResolver = MakeConversionResolver(new List<Type> {
  603. typeof(double), typeof(Extensible<double>)
  604. });
  605. return _FloatResolver;
  606. }
  607. }
  608. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _FloatResolver;
  609. /// <summary>
  610. /// Provides a resolution for __int__
  611. /// </summary>
  612. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ IntResolver {
  613. get {
  614. if (_IntResolver != null) return _IntResolver;
  615. _IntResolver = MakeConversionResolver(new List<Type> {
  616. typeof(int), typeof(Extensible<int>),
  617. typeof(BigInteger), typeof(Extensible<BigInteger>)
  618. });
  619. return _IntResolver;
  620. }
  621. }
  622. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _IntResolver;
  623. /// <summary>
  624. /// Provides a resolution for __long__
  625. /// </summary>
  626. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ BigIntegerResolver {
  627. get {
  628. if (_BigIntegerResolver != null) return _BigIntegerResolver;
  629. _BigIntegerResolver = MakeConversionResolver(new List<Type> {
  630. typeof(BigInteger), typeof(Extensible<BigInteger>),
  631. typeof(int), typeof(Extensible<int>)
  632. });
  633. return _BigIntegerResolver;
  634. }
  635. }
  636. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _BigIntegerResolver;
  637. /// <summary>
  638. /// Provides a resolution for __getitem__
  639. /// </summary>
  640. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ GetItemResolver {
  641. get {
  642. if (_GetItemResolver == null) {
  643. _GetItemResolver = MakeIndexerResolver(false);
  644. }
  645. return _GetItemResolver;
  646. }
  647. }
  648. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _GetItemResolver;
  649. /// <summary>
  650. /// Provides a resolution for __setitem__
  651. /// </summary>
  652. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ SetItemResolver {
  653. get {
  654. if (_SetItemResolver == null) {
  655. _SetItemResolver = MakeIndexerResolver(true);
  656. }
  657. return _SetItemResolver;
  658. }
  659. }
  660. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _SetItemResolver;
  661. #endregion
  662. /// <summary>
  663. /// Provides a resolution for __str__.
  664. /// </summary>
  665. private static MemberGroup/*!*/ StringResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  666. if (type != typeof(double) && type != typeof(float)
  667. #if !CLR2
  668. && type != typeof(Complex)
  669. #endif
  670. ) {
  671. MethodInfo tostr = type.GetMethod("ToString", Type.EmptyTypes);
  672. if (tostr != null && tostr.DeclaringType != typeof(object)) {
  673. return GetInstanceOpsMethod(type, "ToStringMethod");
  674. }
  675. }
  676. return MemberGroup.EmptyGroup;
  677. }
  678. /// <summary>
  679. /// Provides a resolution for __repr__
  680. /// </summary>
  681. private static MemberGroup/*!*/ ReprResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  682. // __repr__ for normal .NET types is special, if we're a Python type then
  683. // we'll use one of the built-in reprs (from object or from the type)
  684. if (!PythonBinder.IsPythonType(type) &&
  685. (!type.IsSealed || !type.IsAbstract)) { // static types don't get __repr__
  686. // check and see if __repr__ has been overridden by the base type.
  687. foreach (Type t in binder.GetContributingTypes(type)) {
  688. if (t == typeof(ObjectOps) && type != typeof(object)) {
  689. break;
  690. }
  691. if (t.GetMember("__repr__").Length > 0) {
  692. // type has a specific __repr__ overload, pick it up normally later
  693. return MemberGroup.EmptyGroup;
  694. }
  695. }
  696. // no override, pick up the default fancy .NET __repr__
  697. return binder.GetBaseInstanceMethod(type, "FancyRepr");
  698. }
  699. return MemberGroup.EmptyGroup;
  700. }
  701. #if !SILVERLIGHT
  702. private static MemberGroup/*!*/ SerializationResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  703. if (type.IsSerializable && !PythonBinder.IsPythonType(type)) {
  704. string methodName = "__reduce_ex__";
  705. if (!TypeOverridesMethod(binder, type, methodName)) {
  706. return GetInstanceOpsMethod(type, "SerializeReduce");
  707. }
  708. }
  709. return MemberGroup.EmptyGroup;
  710. }
  711. /// <summary>
  712. /// Helper to see if the type explicitly overrides the method. This ignores members
  713. /// defined on object.
  714. /// </summary>
  715. private static bool TypeOverridesMethod(MemberBinder/*!*/ binder, Type/*!*/ type, string/*!*/ methodName) {
  716. // check and see if the method has been overridden by the base type.
  717. foreach (Type t in binder.GetContributingTypes(type)) {
  718. if (!PythonBinder.IsPythonType(type) && t == typeof(ObjectOps) && type != typeof(object)) {
  719. break;
  720. }
  721. MemberInfo[] reduce = t.GetMember(methodName);
  722. if (reduce.Length > 0) {
  723. // type has a specific overload
  724. return true;
  725. }
  726. }
  727. return false;
  728. }
  729. #endif
  730. /// <summary>
  731. /// Provides a resolution for __hash__, first looking for IStructuralEquatable.GetHashCode,
  732. /// then IValueEquality.GetValueHashCode.
  733. /// </summary>
  734. private static MemberGroup/*!*/ HashResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  735. #if CLR2
  736. if ((typeof(IStructuralEquatable).IsAssignableFrom(type) ||
  737. typeof(IValueEquality).IsAssignableFrom(type)) && !type.IsInterface) {
  738. #else
  739. if (typeof(IStructuralEquatable).IsAssignableFrom(type) && !type.IsInterface) {
  740. #endif
  741. // check and see if __hash__ has been overridden by the base type.
  742. foreach (Type t in binder.GetContributingTypes(type)) {
  743. // if it's defined on object, it's not overridden
  744. if (t == typeof(ObjectOps) || t == typeof(object)) {
  745. break;
  746. }
  747. MemberInfo[] hash = t.GetMember("__hash__");
  748. if (hash.Length > 0) {
  749. return MemberGroup.EmptyGroup;
  750. }
  751. }
  752. #if CLR2
  753. if (typeof(IStructuralEquatable).IsAssignableFrom(type)) {
  754. return GetInstanceOpsMethod(type, "StructuralHashMethod");
  755. }
  756. if (typeof(IValueEquality).IsAssignableFrom(type)) {
  757. return new MemberGroup(typeof(IValueEquality).GetMethod("GetValueHashCode"));
  758. }
  759. #else
  760. return GetInstanceOpsMethod(type, "StructuralHashMethod");
  761. #endif
  762. }
  763. // otherwise we'll pick up __hash__ from ObjectOps which will call .NET's .GetHashCode therefore
  764. // we don't explicitly search to see if the object overrides GetHashCode here.
  765. return MemberGroup.EmptyGroup;
  766. }
  767. /// <summary>
  768. /// Provides a resolution for __new__. For standard .NET types __new__ resolves to their
  769. /// constructor. For Python types they inherit __new__ from their base class.
  770. ///
  771. /// TODO: Can we just always fallback to object.__new__? If not why not?
  772. /// </summary>
  773. private static MemberGroup/*!*/ NewResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  774. if (type.IsSealed && type.IsAbstract) {
  775. // static types don't have __new__
  776. return MemberGroup.EmptyGroup;
  777. }
  778. bool isPythonType = typeof(IPythonObject).IsAssignableFrom(type);
  779. // check and see if __new__ has been overridden by the base type.
  780. foreach (Type t in binder.GetContributingTypes(type)) {
  781. if (!isPythonType && t == typeof(ObjectOps) && type != typeof(object)) {
  782. break;
  783. }
  784. MemberInfo[] news = t.GetMember("__new__");
  785. if (news.Length > 0) {
  786. // type has a specific __new__ overload, return that for the constructor
  787. return GetExtensionMemberGroup(type, news);
  788. }
  789. }
  790. // type has no Python __new__, just return the .NET constructors if they have
  791. // a custom new
  792. ConstructorInfo[] ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);// CompilerHelpers.GetConstructors(type, binder.DomainManager.Configuration.PrivateBinding, true);
  793. ctors = CompilerHelpers.FilterConstructorsToPublicAndProtected(ctors);
  794. if (!PythonTypeOps.IsDefaultNew(ctors)) {
  795. return new MemberGroup(ctors);
  796. }
  797. // if no ctor w/ parameters are defined, fall back to object.__new__ which
  798. // will ignore all the extra arguments allowing the user to just override
  799. // __init__.
  800. return MemberGroup.EmptyGroup;
  801. }
  802. internal static MemberGroup GetExtensionMemberGroup(Type type, MemberInfo[] news) {
  803. List<MemberTracker> mts = new List<MemberTracker>();
  804. foreach (MemberInfo mi in news) {
  805. if (mi.MemberType == MemberTypes.Method) {
  806. if (mi.DeclaringType.IsAssignableFrom(type)) {
  807. mts.Add(MethodTracker.FromMemberInfo(mi));
  808. } else {
  809. mts.Add(MethodTracker.FromMemberInfo(mi, type));
  810. }
  811. }
  812. }
  813. return new MemberGroup(mts.ToArray());
  814. }
  815. /// <summary>
  816. /// Provides a resolution for next
  817. /// </summary>
  818. private static MemberGroup/*!*/ NextResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  819. if (typeof(IEnumerator).IsAssignableFrom(type)) {
  820. return GetInstanceOpsMethod(type, "NextMethod");
  821. }
  822. return MemberGroup.EmptyGroup;
  823. }
  824. /// <summary>
  825. /// Provides a resolution for __len__
  826. /// </summary>
  827. private static MemberGroup/*!*/ LengthResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  828. if (!type.IsDefined(typeof(DontMapICollectionToLenAttribute), true)) {
  829. if (binder.GetInterfaces(type).Contains(typeof(ICollection))) {
  830. return GetInstanceOpsMethod(type, "LengthMethod");
  831. }
  832. foreach (Type t in binder.GetInterfaces(type)) {
  833. if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>)) {
  834. MethodInfo genMeth = typeof(InstanceOps).GetMethod("GenericLengthMethod");
  835. return new MemberGroup(
  836. MethodTracker.FromMemberInfo(genMeth.MakeGenericMethod(t.GetGenericArguments()), type)
  837. );
  838. }
  839. }
  840. }
  841. return MemberGroup.EmptyGroup;
  842. }
  843. /// <summary>
  844. /// Provides a resolution for __iter__
  845. /// </summary>
  846. private static MemberGroup/*!*/ IterResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  847. if (type == typeof(string)) {
  848. // __iter__ is only exposed in 3.0
  849. if (binder.Binder.Context.PythonOptions.Python30) {
  850. return GetInstanceOpsMethod(type, "IterMethodForString");
  851. }
  852. return MemberGroup.EmptyGroup;
  853. }
  854. if (typeof(Bytes).IsAssignableFrom(type)) {
  855. // __iter__ is only exposed in 3.0
  856. if (binder.Binder.Context.PythonOptions.Python30) {
  857. return GetInstanceOpsMethod(type, "IterMethodForBytes");
  858. }
  859. return MemberGroup.EmptyGroup;
  860. }
  861. foreach (Type t in binder.GetContributingTypes(type)) {
  862. MemberInfo[] news = t.GetMember("__iter__");
  863. if (news.Length > 0) {
  864. // type has a specific __iter__ overload, we'll pick it up later
  865. return MemberGroup.EmptyGroup;
  866. }
  867. }
  868. if (!type.IsDefined(typeof(DontMapIEnumerableToIterAttribute), true)) {
  869. // no special __iter__, use the default.
  870. if (typeof(IEnumerable<>).IsAssignableFrom(type)) {
  871. return GetInstanceOpsMethod(type, "IterMethodForGenericEnumerable");
  872. } else if (typeof(IEnumerable).IsAssignableFrom(type)) {
  873. return GetInstanceOpsMethod(type, "IterMethodForEnumerable");
  874. } else if (typeof(IEnumerator<>).IsAssignableFrom(type)) {
  875. return GetInstanceOpsMethod(type, "IterMethodForGenericEnumerator");
  876. } else if (typeof(IEnumerator).IsAssignableFrom(type)) {
  877. return GetInstanceOpsMethod(type, "IterMethodForEnumerator");
  878. }
  879. }
  880. return MemberGroup.EmptyGroup;
  881. }
  882. /// <summary>
  883. /// Looks for an Equals overload defined on the type and if one is present binds __ne__ to an
  884. /// InstanceOps helper.
  885. /// </summary>
  886. private static MemberGroup/*!*/ FallbackInequalityResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  887. // if object defines __eq__ then we can call the reverse version
  888. if (IncludeOperatorMethod(type, PythonOperationKind.NotEqual)) {
  889. foreach (Type curType in binder.GetContributingTypes(type)) {
  890. MemberGroup mg = binder.GetMember(curType, "Equals");
  891. foreach (MemberTracker mt in mg) {
  892. if (mt.MemberType != TrackerTypes.Method || mt.DeclaringType == typeof(object)) {
  893. continue;
  894. }
  895. MethodTracker method = (MethodTracker)mt;
  896. if ((method.Method.Attributes & MethodAttributes.NewSlot) != 0 ||
  897. method.Method.IsDefined(typeof(PythonHiddenAttribute), false)) {
  898. continue;
  899. }
  900. ParameterInfo[] pis = method.Method.GetParameters();
  901. if (pis.Length == 1) {
  902. if (pis[0].ParameterType == typeof(object)) {
  903. #if CLR2
  904. if (curType == typeof(Type)) {
  905. return new MemberGroup(MethodTracker.FromMemberInfo(typeof(InstanceOps).GetMethod("TypeNotEqualsMethod"), curType));
  906. } else {
  907. return new MemberGroup(MethodTracker.FromMemberInfo(typeof(InstanceOps).GetMethod("NotEqualsMethod"), curType));
  908. }
  909. #else
  910. return new MemberGroup(MethodTracker.FromMemberInfo(typeof(InstanceOps).GetMethod("NotEqualsMethod"), curType));
  911. #endif
  912. }
  913. }
  914. }
  915. }
  916. }
  917. return MemberGroup.EmptyGroup;
  918. }
  919. private static MemberGroup/*!*/ AllResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  920. // static types are like modules and define __all__.
  921. if (type.IsAbstract && type.IsSealed) {
  922. return new MemberGroup(new ExtensionPropertyTracker("__all__", typeof(InstanceOps).GetMethod("Get__all__").MakeGenericMethod(type), null, null, type));
  923. }
  924. return MemberGroup.EmptyGroup;
  925. }
  926. private static MemberGroup/*!*/ DirResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  927. if (type.IsDefined(typeof(DontMapGetMemberNamesToDirAttribute), true)) {
  928. return MemberGroup.EmptyGroup;
  929. }
  930. MemberGroup res = binder.GetMember(type, "GetMemberNames");
  931. if (res == MemberGroup.EmptyGroup &&
  932. !typeof(IPythonObject).IsAssignableFrom(type) &&
  933. typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type)) {
  934. res = GetInstanceOpsMethod(type, "DynamicDir");
  935. }
  936. return res;
  937. }
  938. class DocumentationDescriptor : PythonTypeSlot {
  939. internal override bool TryGetValue(CodeContext context, object instance, PythonType owner, out object value) {
  940. if (owner.IsSystemType) {
  941. value = PythonTypeOps.GetDocumentation(owner.UnderlyingSystemType);
  942. return true;
  943. }
  944. value = null;
  945. return false;
  946. }
  947. internal override bool GetAlwaysSucceeds {
  948. get {
  949. return true;
  950. }
  951. }
  952. internal override bool TrySetValue(CodeContext context, object instance, PythonType owner, object value) {
  953. IPythonObject obj = instance as IPythonObject;
  954. if (obj == null || !obj.PythonType.HasDictionary) {
  955. string name = owner.Name;
  956. if (obj != null) {
  957. name = obj.PythonType.Name;
  958. }
  959. throw PythonOps.AttributeErrorForReadonlyAttribute(name, "__doc__");
  960. }
  961. UserTypeOps.GetDictionary(obj)["__doc__"] = value;
  962. return true;
  963. }
  964. }
  965. private static MemberGroup/*!*/ DocResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  966. if (_docDescr == null) {
  967. _docDescr = new DocumentationDescriptor();
  968. }
  969. return new MemberGroup(new CustomAttributeTracker(type, "__doc__", _docDescr));
  970. }
  971. private static MemberGroup/*!*/ EnterResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  972. if (!type.IsDefined(typeof(DontMapIDisposableToContextManagerAttribute), true) && typeof(IDisposable).IsAssignableFrom(type)) {
  973. return GetInstanceOpsMethod(type, "EnterMethod");
  974. }
  975. return MemberGroup.EmptyGroup;
  976. }
  977. private static MemberGroup/*!*/ ExitResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  978. if (!type.IsDefined(typeof(DontMapIDisposableToContextManagerAttribute), true) && typeof(IDisposable).IsAssignableFrom(type)) {
  979. return GetInstanceOpsMethod(type, "ExitMethod");
  980. }
  981. return MemberGroup.EmptyGroup;
  982. }
  983. private static MemberGroup/*!*/ FormatResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  984. if (typeof(IFormattable).IsAssignableFrom(type)) {
  985. return GetInstanceOpsMethod(type, "Format");
  986. }
  987. return MemberGroup.EmptyGroup;
  988. }
  989. /// <summary>
  990. /// Provides an implementation of __contains__. We can pull contains from:
  991. /// ICollection of T which defines Contains directly
  992. /// IList which defines Contains directly
  993. /// IDictionary which defines Contains directly
  994. /// IDictionary of K,V which defines Contains directly
  995. /// IEnumerable of K which we have an InstaceOps helper for
  996. /// IEnumerable which we have an instance ops helper for
  997. /// IEnumerator of K which we have an InstanceOps helper for
  998. /// IEnumerator which we have an instance ops helper for
  999. ///
  1000. /// String is ignored here because it defines __contains__ via extension methods already.
  1001. ///
  1002. /// The lookup is well ordered and not dependent upon the order of values returned by reflection.
  1003. /// </summary>
  1004. private static MemberGroup/*!*/ ContainsResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  1005. if (type.IsDefined(typeof(DontMapIEnumerableToContainsAttribute), true)) {
  1006. // it's enumerable but doesn't have __contains__
  1007. return MemberGroup.EmptyGroup;
  1008. }
  1009. List<MemberTracker> containsMembers = null;
  1010. IList<Type> intf = binder.GetInterfaces(type);
  1011. // if we get a __contains__ for something w/ a generic typed to object don't look for non-generic versions
  1012. bool hasObjectContains = false;
  1013. // search for IDictionary<K, V> first because it's ICollection<KVP<K, V>> and we want to call ContainsKey
  1014. foreach (Type t in intf) {
  1015. if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDictionary<,>)) {
  1016. if (t.GetGenericArguments()[0] == typeof(object)) {
  1017. hasObjectContains = true;
  1018. }
  1019. if (containsMembers == null) {
  1020. containsMembers = new List<MemberTracker>();
  1021. }
  1022. containsMembers.Add(MethodTracker.FromMemberInfo(t.GetMethod("ContainsKey")));
  1023. }
  1024. }
  1025. if (containsMembers == null) {
  1026. // then look for ICollection<T> for generic __contains__ first if we're not an IDictionary<K, V>
  1027. foreach (Type t in intf) {
  1028. if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>)) {
  1029. if (t.GetGenericArguments()[0] == typeof(object)) {
  1030. hasObjectContains = true;
  1031. }
  1032. if (containsMembers == null) {
  1033. containsMembers = new List<MemberTracker>();
  1034. }
  1035. containsMembers.Add(MethodTracker.FromMemberInfo(t.GetMethod("Contains")));
  1036. }
  1037. }
  1038. }
  1039. if (!hasObjectContains) {
  1040. // look for non-generic contains if we didn't already find an overload which takes
  1041. // object
  1042. if (intf.Contains(typeof(IList))) {
  1043. if (containsMembers == null) {
  1044. containsMembers = new List<MemberTracker>();
  1045. }
  1046. containsMembers.Add(MethodTracker.FromMemberInfo(typeof(IList).GetMethod("Contains")));
  1047. } else if (intf.Contains(typeof(IDictionary))) {
  1048. if (containsMembers == null) {
  1049. containsMembers = new List<MemberTracker>();
  1050. }
  1051. containsMembers.Add(MethodTracker.FromMemberInfo(typeof(IDictionary).GetMethod("Contains")));
  1052. } else if (containsMembers == null) {
  1053. // see if we can produce a contains for IEnumerable
  1054. GetEnumeratorContains(type, intf, ref containsMembers, ref hasObjectContains, typeof(IEnumerable<>), typeof(IEnumerable), String.Empty);
  1055. if (containsMembers == null) {
  1056. GetEnumeratorContains(type, intf, ref containsMembers, ref hasObjectContains, typeof(IEnumerator<>), typeof(IEnumerator), "IEnumerator");
  1057. }
  1058. }
  1059. }
  1060. if (containsMembers != null) {
  1061. return new MemberGroup(containsMembers.ToArray());
  1062. }
  1063. return MemberGroup.EmptyGroup;
  1064. }
  1065. /// <summary>
  1066. /// Helper for IEnumerable/IEnumerator __contains__
  1067. /// </summary>
  1068. private static void GetEnumeratorContains(Type type, IList<Type> intf, ref List<MemberTracker> containsMembers, ref bool hasObjectContains, Type ienumOfT, Type ienum, string name) {
  1069. foreach (Type t in intf) {
  1070. if (t.IsGenericType && t.GetGenericTypeDefinition() == ienumOfT) {
  1071. if (t.GetGenericArguments()[0] == typeof(object)) {
  1072. hasObjectContains = true;
  1073. }
  1074. if (containsMembers == null) {
  1075. containsMembers = new List<MemberTracker>();
  1076. }
  1077. containsMembers.Add(
  1078. (MethodTracker)MethodTracker.FromMemberInfo(
  1079. typeof(InstanceOps).GetMethod("ContainsGenericMethod" + name).MakeGenericMethod(t.GetGenericArguments()[0]),
  1080. t
  1081. )
  1082. );
  1083. }
  1084. }
  1085. if (intf.Contains(type) && !hasObjectContains) {
  1086. if (containsMembers == null) {
  1087. containsMembers = new List<MemberTracker>();
  1088. }
  1089. containsMembers.Add(MethodTracker.FromMemberInfo(typeof(InstanceOps).GetMethod("ContainsMethod" + name), typeof(IEnumerable)));
  1090. }
  1091. }
  1092. private class OneOffOperatorBinder {
  1093. private string/*!*/ _methodName;
  1094. private string/*!*/ _pythonName;
  1095. private PythonOperationKind/*!*/ _op;
  1096. public OneOffOperatorBinder(string/*!*/ methodName, string/*!*/ pythonName, PythonOperationKind opMap) {
  1097. Assert.NotNull(methodName, pythonName, opMap);
  1098. _methodName = methodName;
  1099. _pythonName = pythonName;
  1100. _op = opMap;
  1101. }
  1102. public MemberGroup/*!*/ Resolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  1103. if (type.IsSealed && type.IsAbstract) {
  1104. // static types don't have PythonOperationKind
  1105. return MemberGroup.EmptyGroup;
  1106. }
  1107. foreach (Type t in binder.GetContributingTypes(type)) {
  1108. MemberGroup res = binder.GetMember(t, _methodName);
  1109. if (res.Count > 0) {
  1110. return FilterForwardReverseMethods(_pythonName, res, type, _op);
  1111. }
  1112. }
  1113. return MemberGroup.EmptyGroup;
  1114. }
  1115. }
  1116. private class OneOffPowerBinder {
  1117. private string/*!*/ _pythonName;
  1118. private PythonOperationKind/*!*/ _op;
  1119. public OneOffPowerBinder(string/*!*/ pythonName, PythonOperationKind op) {
  1120. Assert.NotNull(pythonName, op);
  1121. _pythonName = pythonName;
  1122. _op = op;
  1123. }
  1124. public MemberGroup/*!*/ Resolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  1125. if (type.IsSealed && type.IsAbstract) {
  1126. // static types don't have PythonOperationKind
  1127. return MemberGroup.EmptyGroup;
  1128. }
  1129. foreach (Type t in binder.GetContributingTypes(type)) {
  1130. if (t == typeof(BigInteger)) continue;
  1131. MemberGroup res = binder.GetMember(t, "op_Power");
  1132. if (res.Count > 0) {
  1133. return FilterForwardReverseMethods(_pythonName, res, type, _op);
  1134. }
  1135. res = binder.GetMember(t, "Power");
  1136. if (res.Count > 0) {
  1137. return FilterForwardReverseMethods(_pythonName, res, type, _op);
  1138. }
  1139. }
  1140. return MemberGroup.EmptyGroup;
  1141. }
  1142. }
  1143. private static MethodTracker/*!*/[]/*!*/ GetEqualityMethods(Type type, string name) {
  1144. MethodInfo[] mis = GetMethodSet(name, 3);
  1145. MethodTracker[] trackers = new MethodTracker[mis.Length];
  1146. for (int i = 0; i < mis.Length; i++) {
  1147. trackers[i] = (MethodTracker)MethodTracker.FromMemberInfo(mis[i].MakeGenericMethod(type), type);
  1148. }
  1149. return trackers;
  1150. }
  1151. #endregion
  1152. #region Member lookup implementations
  1153. /// <summary>
  1154. /// Base class used for resolving a name into a member on the type.
  1155. /// </summary>
  1156. private abstract class MemberBinder {
  1157. private PythonBinder/*!*/ _binder;
  1158. public MemberBinder(PythonBinder/*!*/ binder) {
  1159. Debug.Assert(binder != null);
  1160. _binder = binder;
  1161. }
  1162. public abstract IList<Type/*!*/>/*!*/ GetContributingTypes(Type/*!*/ t);
  1163. public abstract IList<Type/*!*/>/*!*/ GetInterfaces(Type/*!*/ t);
  1164. /// <summary>
  1165. /// Gets an instance op method for the given type and name.
  1166. ///
  1167. /// Instance ops methods appaer on the base most class that's required to expose it. So
  1168. /// if we have: Array[int], Array, object we'd only add an instance op method to Array and
  1169. /// Array[int] inherits it. It's obviously not on object because if it was there we'd just
  1170. /// put the method in ObjectOps.
  1171. ///
  1172. /// Therefore the different binders expose this at the appropriate times.
  1173. /// </summary>
  1174. public abstract MemberGroup/*!*/ GetBaseInstanceMethod(Type/*!*/ type, params string[] name);
  1175. public abstract MemberGroup/*!*/ GetMember(Type/*!*/ type, string/*!*/ name);
  1176. public PythonBinder/*!*/ Binder {
  1177. get {
  1178. return _binder;
  1179. }
  1180. }
  1181. public ScriptDomainManager/*!*/ DomainManager {
  1182. get {
  1183. return _binder.DomainManager;
  1184. }
  1185. }
  1186. protected MemberGroup/*!*/ GetMember(Type/*!*/ type, string/*!*/ name, BindingFlags flags) {
  1187. Assert.NotNull(type, name);
  1188. MemberInfo[] foundMembers = type.GetMember(name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | flags);
  1189. if (!Binder.DomainManager.Configuration.PrivateBinding) {
  1190. foundMembers = CompilerHelpers.FilterNonVisibleMembers(type, foundMembers);
  1191. }
  1192. MemberGroup members = new MemberGroup(foundMembers);
  1193. // check for generic types w/ arity...
  1194. Type[] types = type.GetNestedTypes(BindingFlags.Public | flags);
  1195. string genName = name + ReflectionUtils.GenericArityDelimiter;
  1196. List<Type> genTypes = null;
  1197. foreach (Type t in types) {
  1198. if (t.Name.StartsWith(genName)) {
  1199. if (genTypes == null) genTypes = new List<Type>();
  1200. genTypes.Add(t);
  1201. }
  1202. }
  1203. if (genTypes != null) {
  1204. List<MemberTracker> mt = new List<MemberTracker>(members);
  1205. foreach (Type t in genTypes) {
  1206. mt.Add(MemberTracker.FromMemberInfo(t));
  1207. }
  1208. return new MemberGroup(mt.ToArray());
  1209. }
  1210. if (members.Count == 0) {
  1211. if ((flags & BindingFlags.DeclaredOnly) == 0) {
  1212. members = Binder.GetAllExtensionMembers(type, name);
  1213. } else {
  1214. members = Binder.GetExtensionMembers(type, name);
  1215. }
  1216. }
  1217. return members;
  1218. }
  1219. }
  1220. /// <summary>
  1221. /// MemberBinder which searches the entire type hierarchy and their extension types to find a member.
  1222. /// </summary>
  1223. private class ResolveBinder : MemberBinder {
  1224. public ResolveBinder(PythonBinder/*!*/ binder)
  1225. : base(binder) {
  1226. }
  1227. public override IList<Type/*!*/>/*!*/ GetInterfaces(Type/*!*/ t) {
  1228. return t.GetInterfaces();
  1229. }
  1230. public override MemberGroup/*!*/ GetBaseInstanceMethod(Type/*!*/ type, params string[] name) {
  1231. return GetInstanceOpsMethod(type, name);
  1232. }
  1233. public override IList<Type/*!*/>/*!*/ GetContributingTypes(Type/*!*/ t) {
  1234. Debug.Assert(t != null);
  1235. List<Type> res = new List<Type>();
  1236. IList<PythonType> mro = DynamicHelpers.GetPythonTypeFromType(t).ResolutionOrder;
  1237. foreach (PythonType pt in mro) {
  1238. res.Add(pt.UnderlyingSystemType);
  1239. }
  1240. foreach (PythonType pt in mro) {
  1241. res.AddRange(Binder.GetExtensionTypesInternal(pt.UnderlyingSystemType));
  1242. }
  1243. if (t.IsInterface) {
  1244. foreach (Type iface in t.GetInterfaces()) {
  1245. res.Add(iface);
  1246. }
  1247. }
  1248. return res;
  1249. }
  1250. public override MemberGroup GetMember(Type type, string name) {
  1251. return GetMember(type, name, 0);
  1252. }
  1253. }
  1254. /// <summary>
  1255. /// MemberBinder which searches only the current type and it's extension types to find a member.
  1256. /// </summary>
  1257. private class LookupBinder : MemberBinder {
  1258. public LookupBinder(PythonBinder/*!*/ binder)
  1259. : base(binder) {
  1260. }
  1261. public override IList<Type/*!*/>/*!*/ GetInterfaces(Type/*!*/ t) {
  1262. if (t.IsInterface) {
  1263. return t.GetInterfaces();
  1264. }
  1265. Type[] allInterfaces = t.GetInterfaces();
  1266. List<Type> res = new List<Type>();
  1267. foreach (Type intf in allInterfaces) {
  1268. try {
  1269. InterfaceMapping imap = t.GetInterfaceMap(intf);
  1270. foreach (MethodInfo mi in imap.TargetMethods) {
  1271. if (mi != null && mi.DeclaringType == t) {
  1272. res.Add(intf);
  1273. break;
  1274. }
  1275. }
  1276. } catch (ArgumentException) {
  1277. // this fails when the CLR is manufacturing an interface
  1278. // type for a built in type. For example IList<string>
  1279. // for Array[str]. This can be reproed by doing:
  1280. //
  1281. // import System
  1282. // System.Array[str].__dict__['__contains__']
  1283. // __contains__ is actually inherited from Array's IList
  1284. // implementation but IList<str> interferes here.
  1285. }
  1286. }
  1287. return res;
  1288. }
  1289. public override MemberGroup/*!*/ GetBaseInstanceMethod(Type/*!*/ type, params string[] name) {
  1290. if (type.BaseType == typeof(object) || type.BaseType == typeof(ValueType)) {
  1291. return GetInstanceOpsMethod(type, name);
  1292. }
  1293. return MemberGroup.EmptyGroup;
  1294. }
  1295. public override IList<Type/*!*/>/*!*/ GetContributingTypes(Type/*!*/ t) {
  1296. Debug.Assert(t != null);
  1297. List<Type> res = new List<Type>();
  1298. res.Add(t);
  1299. res.AddRange(Binder.GetExtensionTypesInternal(t));
  1300. return res;
  1301. }
  1302. public override MemberGroup GetMember(Type type, string name) {
  1303. return GetMember(type, name, BindingFlags.DeclaredOnly);
  1304. }
  1305. }
  1306. #endregion
  1307. #region Private implementation details
  1308. /// <summary>
  1309. /// Primary worker for getting the member(s) associated with a single name. Can be called with different MemberBinder's to alter the
  1310. /// scope of the search.
  1311. /// </summary>
  1312. private static MemberGroup/*!*/ GetMemberGroup(MemberBinder/*!*/ memberBinder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  1313. foreach (MemberResolver resolver in _resolvers) {
  1314. MemberGroup/*!*/ group = resolver.ResolveMember(memberBinder, action, type, name);
  1315. if (group.Count > 0) {
  1316. return group;
  1317. }
  1318. }
  1319. return MemberGroup.EmptyGroup;
  1320. }
  1321. /// <summary>
  1322. /// Primary worker for returning a list of all members in a type. Can be called with different MemberBinder's to alter the scope
  1323. /// of the search.
  1324. /// </summary>
  1325. private static IList<ResolvedMember/*!*/>/*!*/ GetResolvedMembers(MemberBinder/*!*/ memberBinder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  1326. List<ResolvedMember> res = new List<ResolvedMember>();
  1327. foreach (MemberResolver resolver in _resolvers) {
  1328. res.AddRange(resolver.ResolveMembers(memberBinder, action, type));
  1329. }
  1330. return res;
  1331. }
  1332. /// <summary>
  1333. /// Helper to get a MemberGroup for methods declared on InstanceOps
  1334. /// </summary>
  1335. private static MemberGroup/*!*/ GetInstanceOpsMethod(Type/*!*/ extends, params string[]/*!*/ names) {
  1336. Assert.NotNull(extends, names);
  1337. MethodTracker[] trackers = new MethodTracker[names.Length];
  1338. for (int i = 0; i < names.Length; i++) {
  1339. trackers[i] = (MethodTracker)MemberTracker.FromMemberInfo(typeof(InstanceOps).GetMethod(names[i]), extends);
  1340. }
  1341. return new MemberGroup(trackers);
  1342. }
  1343. /// <summary>
  1344. /// Helper to get the proper typecasting method, according to the following precedence rules:
  1345. ///
  1346. /// 1. Strongest (most specific) declaring type
  1347. /// 2. Strongest (most specific) parameter type
  1348. /// 3. Type of conversion
  1349. /// i. Implicit
  1350. /// ii. Explicit
  1351. /// 4. Return type (order specified in toTypes)
  1352. /// </summary>
  1353. private static MethodInfo FindCastMethod(MemberBinder/*!*/ binder, Type/*!*/ fromType, List<Type>/*!*/ toTypes) {
  1354. MethodInfo cast = null;
  1355. ParameterInfo[] castParams = null;
  1356. foreach (Type t in binder.GetContributingTypes(fromType)) {
  1357. foreach (string castName in GetCastNames(fromType, toTypes[0])) {
  1358. foreach (MemberInfo member in t.GetMember(castName)) {
  1359. MethodInfo method;
  1360. ParameterInfo[] methodParams;
  1361. // Necessary conditions
  1362. if (member.MemberType != MemberTypes.Method) {
  1363. continue;
  1364. }
  1365. method = (MethodInfo)member;
  1366. if (!toTypes.Contains(method.ReturnType) ||
  1367. (methodParams = method.GetParameters()).Length != 1) {
  1368. continue;
  1369. }
  1370. // Precedence rule 1
  1371. if (cast == null || method.DeclaringType.IsSubclassOf(cast.DeclaringType)) {
  1372. cast = method;
  1373. castParams = methodParams;
  1374. continue;
  1375. } else if (method.DeclaringType != cast.DeclaringType) {
  1376. continue;
  1377. }
  1378. // Precedence rule 2
  1379. if (methodParams[0].ParameterType.IsSubclassOf(castParams[0].ParameterType)) {
  1380. cast = method;
  1381. castParams = methodParams;
  1382. continue;
  1383. } else if (castParams[0].ParameterType != methodParams[0].ParameterType) {
  1384. continue;
  1385. }
  1386. // Precedence rule 3
  1387. if (method.Name != cast.Name) {
  1388. if (method.Name == "op_Implicit") {
  1389. cast = method;
  1390. castParams = methodParams;
  1391. }
  1392. continue;
  1393. }
  1394. // Precedence rule 4:
  1395. foreach (Type toType in toTypes) {
  1396. if (method.ReturnType == toType) {
  1397. cast = method;
  1398. castParams = methodParams;
  1399. } else if (cast.ReturnType == toType) {
  1400. break;
  1401. }
  1402. }
  1403. }
  1404. }
  1405. }
  1406. return cast;
  1407. }
  1408. private static readonly string[] CastNames = new[] { "op_Implicit", "op_Explicit" };
  1409. private static string[] GetCastNames(Type fromType, Type toType) {
  1410. if (PythonBinder.IsPythonType(fromType)) {
  1411. return CastNames;
  1412. }
  1413. return new[] { "op_Implicit", "op_Explicit", "ConvertTo" + toType.Name };
  1414. }
  1415. /// <summary>
  1416. /// Helper for creating a typecast resolver
  1417. /// </summary>
  1418. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ MakeConversionResolver(List<Type> castPrec) {
  1419. return delegate(MemberBinder/*!*/ binder, Type/*!*/ type) {
  1420. MethodInfo cast = FindCastMethod(binder, type, castPrec);
  1421. if (cast != null) {
  1422. MethodTracker tracker = (MethodTracker)MemberTracker.FromMemberInfo(cast, type);
  1423. return new MemberGroup(tracker);
  1424. }
  1425. return MemberGroup.EmptyGroup;
  1426. };
  1427. }
  1428. /// <summary>
  1429. /// Helper for creating __getitem__/__setitem__ resolvers
  1430. /// </summary>
  1431. /// <param name="set">false for a getter, true for a setter</param>
  1432. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ MakeIndexerResolver(bool set) {
  1433. return delegate(MemberBinder/*!*/ binder, Type/*!*/ type) {
  1434. List<MemberInfo> members = null;
  1435. foreach (MemberInfo member in type.GetDefaultMembers()) {
  1436. PropertyInfo property = member as PropertyInfo;
  1437. if (property != null) {
  1438. MethodInfo accessor;
  1439. if (!set) {
  1440. accessor = property.GetGetMethod();
  1441. } else {
  1442. accessor = property.GetSetMethod();
  1443. }
  1444. if (accessor != null) {
  1445. members = members ?? new List<MemberInfo>();
  1446. members.Add(accessor);
  1447. }
  1448. }
  1449. }
  1450. if (members == null) {
  1451. return MemberGroup.EmptyGroup;
  1452. } else {
  1453. return new MemberGroup(members.ToArray());
  1454. }
  1455. };
  1456. }
  1457. /// <summary>
  1458. /// Filters out methods which are present on standard .NET types but shouldn't be there in Python
  1459. /// </summary>
  1460. internal static bool IncludeOperatorMethod(Type/*!*/ t, PythonOperationKind op) {
  1461. if (t == typeof(string) && op == PythonOperationKind.Compare) {
  1462. // string doesn't define __cmp__, just __lt__ and friends
  1463. return false;
  1464. }
  1465. // numeric types in python don't define equality, just __cmp__
  1466. if (t == typeof(bool) ||
  1467. (Converter.IsNumeric(t) && t != typeof(Complex) && t != typeof(double) && t != typeof(float))) {
  1468. switch (op) {
  1469. case PythonOperationKind.Equal:
  1470. case PythonOperationKind.NotEqual:
  1471. case PythonOperationKind.GreaterThan:
  1472. case PythonOperationKind.LessThan:
  1473. case PythonOperationKind.GreaterThanOrEqual:
  1474. case PythonOperationKind.LessThanOrEqual:
  1475. return false;
  1476. }
  1477. }
  1478. return true;
  1479. }
  1480. /// <summary>
  1481. /// When private binding is enabled we can have a collision between the private Event
  1482. /// and private field backing the event. We filter this out and favor the event.
  1483. ///
  1484. /// This matches the v1.0 behavior of private binding.
  1485. /// </summary>
  1486. private static MemberGroup/*!*/ FilterFieldAndEvent(MemberGroup/*!*/ members) {
  1487. Debug.Assert(members != null);
  1488. TrackerTypes mt = TrackerTypes.None;
  1489. foreach (MemberTracker mi in members) {
  1490. mt |= mi.MemberType;
  1491. }
  1492. if (mt == (TrackerTypes.Event | TrackerTypes.Field)) {
  1493. List<MemberTracker> res = new List<MemberTracker>();
  1494. foreach (MemberTracker mi in members) {
  1495. if (mi.MemberType == TrackerTypes.Event) {
  1496. res.Add(mi);
  1497. }
  1498. }
  1499. return new MemberGroup(res.ToArray());
  1500. }
  1501. return members;
  1502. }
  1503. /// <summary>
  1504. /// Filters down to include only protected methods
  1505. /// </summary>
  1506. private static bool ProtectedOnly(MemberInfo/*!*/ input) {
  1507. Debug.Assert(input != null);
  1508. switch (input.MemberType) {
  1509. case MemberTypes.Method:
  1510. return ((MethodInfo)input).IsProtected();
  1511. case MemberTypes.Property:
  1512. MethodInfo mi = ((PropertyInfo)input).GetGetMethod(true);
  1513. if (mi != null) return ProtectedOnly(mi);
  1514. return false;
  1515. case MemberTypes.Field:
  1516. return ((FieldInfo)input).IsProtected();
  1517. case MemberTypes.NestedType:
  1518. return ((Type)input).IsProtected();
  1519. default:
  1520. return false;
  1521. }
  1522. }
  1523. internal static bool IsReverseOperator(PythonOperationKind op) {
  1524. return (op & PythonOperationKind.Reversed) != 0;
  1525. }
  1526. /// <summary>
  1527. /// If an operator is a reverisble operator (e.g. addition) then we need to filter down to just the forward/reverse
  1528. /// versions of the .NET method. For example consider:
  1529. ///
  1530. /// String.op_Multiplication(int, string)
  1531. /// String.op_Multiplication(string, int)
  1532. ///
  1533. /// If this method were defined on string it defines that you can do:
  1534. /// 2 * 'abc'
  1535. /// or:
  1536. /// 'abc' * 2
  1537. ///
  1538. /// either of which will produce 'abcabc'. The 1st form is considered the reverse form because it is declared on string
  1539. /// but takes a non-string for the 1st argument. The 2nd is considered the forward form because it takes a string as the
  1540. /// 1st argument.
  1541. ///
  1542. /// When dynamically dispatching for 2 * 'abc' we'll first try __mul__ on int, which will fail with a string argument. Then we'll try
  1543. /// __rmul__ on a string which will succeed and dispatch to the (int, string) overload.
  1544. ///
  1545. /// For multiplication in this case it's not too interesting because it's commutative. For addition this might be more interesting
  1546. /// if, for example, we had unicode and ASCII strings. In that case Unicode strings would define addition taking both unicode and
  1547. /// ASCII strings in both forms.
  1548. /// </summary>
  1549. private static MemberGroup/*!*/ FilterForwardReverseMethods(string name, MemberGroup/*!*/ group, Type/*!*/ type, PythonOperationKind oper) {
  1550. List<MethodTracker> res = new List<MethodTracker>(group.Count);
  1551. PythonOperationKind reversed = Symbols.OperatorToReverseOperator(oper);
  1552. foreach (MemberTracker mt in group) {
  1553. if (mt.MemberType != TrackerTypes.Method) {
  1554. continue;
  1555. }
  1556. MethodTracker mTracker = (MethodTracker)mt;
  1557. if (reversed == PythonOperationKind.None) {
  1558. res.Add(mTracker);
  1559. continue;
  1560. }
  1561. MethodInfo method = mTracker.Method;
  1562. if (!method.IsStatic) {
  1563. if (!IsReverseOperator(oper)) {
  1564. res.Add(mTracker);
  1565. }
  1566. continue;
  1567. }
  1568. ParameterInfo[] parms = method.GetParameters();
  1569. int ctxOffset = (parms.Length > 0 && parms[0].ParameterType == typeof(CodeContext)) ? 1 : 0;
  1570. bool regular;
  1571. bool reverse;
  1572. if ((parms.Length - ctxOffset) == 2) {
  1573. Type param1Type = parms[0 + ctxOffset].ParameterType;
  1574. Type param2Type = parms[1 + ctxOffset].ParameterType;
  1575. // both parameters could be typed to object in which case we want to add
  1576. // the method as whatever we're being requested for here. One example of this
  1577. // is EnumOps which can't be typed to Enum.
  1578. if (param1Type == typeof(object) && param2Type == typeof(object)) {
  1579. regular = !IsReverseOperator(oper);
  1580. reverse = IsReverseOperator(oper);
  1581. } else {
  1582. regular = parms.Length > 0 && AreTypesCompatible(param1Type, type);
  1583. reverse = ((oper & PythonOperationKind.Comparison) == 0) && parms.Length > 1 && AreTypesCompatible(param2Type, type);
  1584. }
  1585. if (IsReverseOperator(oper)) {
  1586. if (reverse) {
  1587. res.Add(mTracker);
  1588. }
  1589. } else {
  1590. if (regular) {
  1591. res.Add(mTracker);
  1592. }
  1593. }
  1594. } else {
  1595. res.Add(mTracker);
  1596. }
  1597. }
  1598. if (res.Count == 0) {
  1599. return MemberGroup.EmptyGroup;
  1600. }
  1601. return new MemberGroup(new OperatorTracker(type, name, IsReverseOperator(oper), res.ToArray()));
  1602. }
  1603. /// <summary>
  1604. /// Checks to see if the parameter type and the declaring type are compatible to determine
  1605. /// if an operator is forward or reverse.
  1606. /// </summary>
  1607. private static bool AreTypesCompatible(Type paramType, Type declaringType) {
  1608. if (paramType == typeof(object)) {
  1609. // we may have:
  1610. // op_Add(object, someType)
  1611. // op_Add(someType, object)
  1612. // we should recognize this as forward and reverse
  1613. return declaringType == typeof(object);
  1614. }
  1615. // avoid getting/creating the PythonType if possible
  1616. if (paramType == declaringType || declaringType.IsSubclassOf(paramType)) {
  1617. return true;
  1618. } else if (declaringType.IsSubclassOf(typeof(Extensible<>).MakeGenericType(paramType))) {
  1619. return true;
  1620. }
  1621. return DynamicHelpers.GetPythonTypeFromType(declaringType).IsSubclassOf(DynamicHelpers.GetPythonTypeFromType(paramType));
  1622. }
  1623. private static void EnsureOperatorTable() {
  1624. if (_pythonOperatorTable == null) {
  1625. _pythonOperatorTable = InitializeOperatorTable();
  1626. }
  1627. }
  1628. private static MemberGroup/*!*/ FilterSpecialNames(MemberGroup/*!*/ group, string/*!*/ name, MemberRequestKind/*!*/ action) {
  1629. Assert.NotNull(group, name, action);
  1630. bool filter = true;
  1631. if (action == MemberRequestKind.Invoke ||
  1632. action == MemberRequestKind.Convert ||
  1633. action == MemberRequestKind.Operation) {
  1634. filter = false;
  1635. }
  1636. if (!IsPythonRecognizedOperator(name)) {
  1637. filter = false;
  1638. }
  1639. List<MemberTracker> mts = null;
  1640. for (int i = 0; i < group.Count; i++) {
  1641. MemberTracker mt = group[i];
  1642. bool skip = false;
  1643. if (mt.MemberType == TrackerTypes.Method) {
  1644. MethodTracker meth = (MethodTracker)mt;
  1645. if (meth.Method.IsSpecialName && mt.Name != "op_Implicit" && mt.Name != "op_Explicit") {
  1646. if (!IsPropertyWithParameters(meth)) {
  1647. skip = true;
  1648. }
  1649. }
  1650. if (meth.Method.IsDefined(typeof(ClassMethodAttribute), true)) {
  1651. return new MemberGroup(new ClassMethodTracker(group));
  1652. }
  1653. } else if (mt.MemberType == TrackerTypes.Property) {
  1654. PropertyTracker pt = (PropertyTracker)mt;
  1655. if (name == pt.Name && pt.GetIndexParameters().Length > 0 && IsPropertyDefaultMember(pt)) {
  1656. // exposed via __*item__, not the property name
  1657. skip = true;
  1658. }
  1659. } else if (mt.MemberType == TrackerTypes.Field) {
  1660. FieldInfo fi = ((FieldTracker)mt).Field;
  1661. if (fi.IsDefined(typeof(SlotFieldAttribute), false)) {
  1662. if (mts == null) {
  1663. mts = MakeListWithPreviousMembers(group, mts, i);
  1664. mt = new CustomAttributeTracker(mt.DeclaringType, mt.Name, (PythonTypeSlot)fi.GetValue(null));
  1665. }
  1666. }
  1667. }
  1668. if (skip && filter) {
  1669. if (mts == null) {
  1670. // add any ones we skipped...
  1671. mts = MakeListWithPreviousMembers(group, mts, i);
  1672. }
  1673. } else if (mts != null) {
  1674. mts.Add(mt);
  1675. }
  1676. }
  1677. if (mts != null) {
  1678. if (mts.Count == 0) {
  1679. return MemberGroup.EmptyGroup;
  1680. }
  1681. return new MemberGroup(mts.ToArray());
  1682. }
  1683. return group;
  1684. }
  1685. private static bool IsPropertyWithParameters(MethodTracker/*!*/ meth) {
  1686. if (meth.Method.Name.StartsWith("get_")) {
  1687. if (!IsMethodDefaultMember(meth)) {
  1688. ParameterInfo[] args = meth.Method.GetParameters();
  1689. if (args.Length > 0) {
  1690. return true;
  1691. }
  1692. }
  1693. } else if (meth.Method.Name.StartsWith("set_")) {
  1694. if (!IsMethodDefaultMember(meth)) {
  1695. ParameterInfo[] args = meth.Method.GetParameters();
  1696. if (args.Length > 1) {
  1697. return true;
  1698. }
  1699. }
  1700. }
  1701. return false;
  1702. }
  1703. /// <summary>
  1704. /// Checks to see if this is an operator method which Python recognizes. For example
  1705. /// op_Comma is not recognized by Python and therefore should exposed to the user as
  1706. /// a method that is callable by name.
  1707. /// </summary>
  1708. private static bool IsPythonRecognizedOperator(string name) {
  1709. if (name.StartsWith("get_") || name.StartsWith("set_")) {
  1710. return true;
  1711. }
  1712. // Python recognized operator names that aren't DLR standard names
  1713. switch (name) {
  1714. case "Abs":
  1715. case "TrueDivide":
  1716. case "FloorDivide":
  1717. case "Power":
  1718. case "DivMod":
  1719. return true;
  1720. }
  1721. bool isPythonRecognizedOperator = false;
  1722. OperatorMapping oi = OperatorMapping.GetOperatorMapping(name);
  1723. if (oi != null) {
  1724. EnsureOperatorTable();
  1725. if(_pythonOperatorTable.ContainsValue(oi.Operator)) {
  1726. isPythonRecognizedOperator = true;
  1727. }
  1728. }
  1729. return isPythonRecognizedOperator;
  1730. }
  1731. private static bool IsPropertyDefaultMember(PropertyTracker pt) {
  1732. foreach (MemberInfo mem in pt.DeclaringType.GetDefaultMembers()) {
  1733. if (mem.Name == pt.Name) {
  1734. return true;
  1735. }
  1736. }
  1737. return false;
  1738. }
  1739. private static bool IsMethodDefaultMember(MethodTracker pt) {
  1740. foreach (MemberInfo mem in pt.DeclaringType.GetDefaultMembers()) {
  1741. if (mem.MemberType == MemberTypes.Property) {
  1742. PropertyInfo pi = (PropertyInfo)mem;
  1743. if (pi.GetGetMethod() == pt.Method ||
  1744. pi.GetSetMethod() == pt.Method) {
  1745. return true;
  1746. }
  1747. }
  1748. }
  1749. return false;
  1750. }
  1751. private static List<MemberTracker> MakeListWithPreviousMembers(MemberGroup group, List<MemberTracker> mts, int i) {
  1752. mts = new List<MemberTracker>(i);
  1753. for (int j = 0; j < i; j++) {
  1754. mts.Add(group[j]);
  1755. }
  1756. return mts;
  1757. }
  1758. private static MethodInfo[] GetMethodSet(string name, int expected) {
  1759. MethodInfo[] methods = typeof(InstanceOps).GetMethods();
  1760. MethodInfo[] filtered = new MethodInfo[expected];
  1761. int j = 0;
  1762. for (int i = 0; i < methods.Length; i++) {
  1763. if (methods[i].Name == name) {
  1764. filtered[j++] = methods[i];
  1765. #if !DEBUG
  1766. if (j == expected) break;
  1767. #endif
  1768. }
  1769. }
  1770. Debug.Assert(j == expected);
  1771. return filtered;
  1772. }
  1773. #endregion
  1774. }
  1775. }