PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/Types/TypeInfo.cs

http://github.com/IronLanguages/main
C# | 1371 lines | 923 code | 211 blank | 237 comment | 292 complexity | 62580c38bd987ade39de8d0bb02e0855 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Linq;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.Reflection;
  21. using System.Dynamic;
  22. using System.Threading;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Actions;
  25. using Microsoft.Scripting.Generation;
  26. using Microsoft.Scripting.Runtime;
  27. using Microsoft.Scripting.Utils;
  28. using IronPython.Runtime.Binding;
  29. using IronPython.Runtime.Exceptions;
  30. using IronPython.Runtime.Operations;
  31. #if FEATURE_NUMERICS
  32. using System.Numerics;
  33. #else
  34. using Microsoft.Scripting.Math;
  35. using Complex = Microsoft.Scripting.Math.Complex64;
  36. #endif
  37. namespace IronPython.Runtime.Types {
  38. /// <summary>
  39. /// Helpers for interacting w/ .NET types. This includes:
  40. ///
  41. /// Member resolution via GetMember/GetMembers. This performs a member lookup which includes the registered
  42. /// extension types in the PythonBinder. Internally the class has many MemberResolver's which provide
  43. /// the various resolution behaviors.
  44. ///
  45. /// Cached member access - this is via static classes such as Object and provides various MemberInfo's so we're
  46. /// not constantly looking up via reflection.
  47. /// </summary>
  48. internal static partial class TypeInfo {
  49. /// <summary> list of resolvers which we run to resolve items </summary>
  50. private static readonly MemberResolver/*!*/[]/*!*/ _resolvers = MakeResolverTable();
  51. [MultiRuntimeAware]
  52. private static DocumentationDescriptor _docDescr;
  53. [MultiRuntimeAware]
  54. internal static Dictionary<string, PythonOperationKind> _pythonOperatorTable;
  55. #region Public member resolution
  56. /// <summary>
  57. /// Gets the statically known member from the type with the specific name. Searches the entire type hierarchy to find the specified member.
  58. /// </summary>
  59. public static MemberGroup/*!*/ GetMemberAll(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  60. Assert.NotNull(binder, action, type, name);
  61. PerfTrack.NoteEvent(PerfTrack.Categories.ReflectedTypes, String.Format("ResolveMember: {0} {1}", type.Name, name));
  62. return GetMemberGroup(new ResolveBinder(binder), action, type, name);
  63. }
  64. /// <summary>
  65. /// Gets all the statically known members from the specified type. Searches the entire type hierarchy to get all possible members.
  66. ///
  67. /// The result may include multiple resolution. It is the callers responsibility to only treat the 1st one by name as existing.
  68. /// </summary>
  69. public static IList<ResolvedMember/*!*/>/*!*/ GetMembersAll(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  70. Assert.NotNull(binder, action, type);
  71. return GetResolvedMembers(new ResolveBinder(binder), action, type);
  72. }
  73. /// <summary>
  74. /// Gets the statically known member from the type with the specific name. Searches only the specified type to find the member.
  75. /// </summary>
  76. public static MemberGroup/*!*/ GetMember(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  77. Assert.NotNull(binder, action, type, name);
  78. PerfTrack.NoteEvent(PerfTrack.Categories.ReflectedTypes, String.Format("LookupMember: {0} {1}", type.Name, name));
  79. return GetMemberGroup(new LookupBinder(binder), action, type, name);
  80. }
  81. /// <summary>
  82. /// Gets all the statically known members from the specified type. Searches only the specified type to find the members.
  83. ///
  84. /// The result may include multiple resolution. It is the callers responsibility to only treat the 1st one by name as existing.
  85. /// </summary>
  86. public static IList<ResolvedMember/*!*/>/*!*/ GetMembers(PythonBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  87. Assert.NotNull(binder, action, type);
  88. return GetResolvedMembers(new LookupBinder(binder), action, type);
  89. }
  90. #endregion
  91. #region Cached type members
  92. public static class _Object {
  93. public new static readonly MethodInfo/*!*/ GetType = typeof(object).GetMethod("GetType");
  94. }
  95. public static class _IPythonObject {
  96. public static readonly PropertyInfo/*!*/ PythonType = typeof(IPythonObject).GetProperty("PythonType");
  97. public static readonly PropertyInfo/*!*/ Dict = typeof(IPythonObject).GetProperty("Dict");
  98. }
  99. public static class _PythonOps {
  100. public static readonly MethodInfo/*!*/ SlotTryGetBoundValue = typeof(PythonOps).GetMethod("SlotTryGetBoundValue");
  101. public static readonly MethodInfo/*!*/ GetTypeVersion = typeof(PythonOps).GetMethod("GetTypeVersion");
  102. public static readonly MethodInfo/*!*/ CheckTypeVersion = typeof(PythonOps).GetMethod("CheckTypeVersion");
  103. }
  104. public static class _OperationFailed {
  105. public static readonly FieldInfo/*!*/ Value = typeof(OperationFailed).GetField("Value");
  106. }
  107. public static class _PythonDictionary {
  108. public static readonly MethodInfo/*!*/ TryGetvalue = typeof(PythonDictionary).GetMethod("TryGetValue");
  109. }
  110. public static class _PythonGenerator {
  111. public static readonly ConstructorInfo Ctor = typeof(PythonGenerator).GetConstructor(new Type[] { typeof(PythonFunction) });
  112. }
  113. #endregion
  114. #region MemberResolver implementations and infrastructure
  115. /// <summary>
  116. /// Abstract class used for resolving members. This provides two methods of member look. The first is looking
  117. /// up a single member by name. The other is getting all of the members.
  118. ///
  119. /// There are various subclasses of this which have different methods of resolving the members. The primary
  120. /// function of the resolvers are to provide the name->value lookup. They also need to provide a simple name
  121. /// enumerator. The enumerator is kept simple because it's allowed to return duplicate names as well as return
  122. /// names of members that don't exist. The base MemberResolver will then verify their existance as well as
  123. /// filter duplicates.
  124. /// </summary>
  125. abstract class MemberResolver {
  126. /// <summary>
  127. /// Looks up an individual member and returns a MemberGroup with the given members.
  128. /// </summary>
  129. public abstract MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name);
  130. /// <summary>
  131. /// Returns a list of members that exist on the type. The ResolvedMember structure indicates both
  132. /// the name and provides the MemberGroup.
  133. /// </summary>
  134. public IList<ResolvedMember/*!*/>/*!*/ ResolveMembers(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  135. Dictionary<string, ResolvedMember> members = new Dictionary<string, ResolvedMember>();
  136. foreach (string name in GetCandidateNames(binder, action, type)) {
  137. if (members.ContainsKey(name)) {
  138. continue;
  139. }
  140. MemberGroup member = ResolveMember(binder, action, type, name);
  141. if (member.Count > 0) {
  142. members[name] = new ResolvedMember(name, member);
  143. }
  144. }
  145. ResolvedMember[] res = new ResolvedMember[members.Count];
  146. members.Values.CopyTo(res, 0);
  147. return res;
  148. }
  149. /// <summary>
  150. /// Returns a list of possible members which could exist. ResolveMember needs to be called to verify their existance. Duplicate
  151. /// names can also be returned.
  152. /// </summary>
  153. protected abstract IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type);
  154. }
  155. /// <summary>
  156. /// One off resolver for various special methods which are known by name. A delegate is provided to provide the actual member which
  157. /// will be resolved.
  158. /// </summary>
  159. class OneOffResolver : MemberResolver {
  160. private string/*!*/ _name;
  161. private Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ _resolver;
  162. public OneOffResolver(string/*!*/ name, Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ resolver) {
  163. Assert.NotNull(name, resolver);
  164. _name = name;
  165. _resolver = resolver;
  166. }
  167. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  168. Assert.NotNull(binder, action, type, name);
  169. if (name == _name) {
  170. return _resolver(binder, type);
  171. }
  172. return MemberGroup.EmptyGroup;
  173. }
  174. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  175. yield return _name;
  176. }
  177. }
  178. /// <summary>
  179. /// Standard resolver for looking up .NET members. Uses reflection to get the members by name.
  180. /// </summary>
  181. class StandardResolver : MemberResolver {
  182. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  183. if (name == ".ctor" || name == ".cctor") return MemberGroup.EmptyGroup;
  184. // normal binding
  185. MemberGroup res;
  186. foreach (Type curType in binder.GetContributingTypes(type)) {
  187. res = FilterSpecialNames(binder.GetMember(curType, name), name, action);
  188. if (res.Count > 0) {
  189. return res;
  190. }
  191. }
  192. if (type.IsInterface) {
  193. foreach (Type t in type.GetInterfaces()) {
  194. res = FilterSpecialNames(binder.GetMember(t, name), name, action);
  195. if (res.Count > 0) {
  196. return res;
  197. }
  198. }
  199. }
  200. return MemberGroup.EmptyGroup;
  201. }
  202. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  203. foreach (Type curType in binder.GetContributingTypes(type)) {
  204. foreach (MemberInfo mi in curType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
  205. if (mi.MemberType == MemberTypes.Method) {
  206. MethodInfo meth = (MethodInfo)mi;
  207. if (meth.IsSpecialName) {
  208. if (meth.IsDefined(typeof(PropertyMethodAttribute), true)) {
  209. if (meth.Name.StartsWith("Get") || meth.Name.StartsWith("Set")) {
  210. yield return meth.Name.Substring(3);
  211. } else {
  212. Debug.Assert(meth.Name.StartsWith("Delete"));
  213. yield return meth.Name.Substring(6);
  214. }
  215. }
  216. continue;
  217. }
  218. }
  219. yield return mi.Name;
  220. }
  221. }
  222. }
  223. }
  224. /// <summary>
  225. /// Resolves methods mapped to __eq__ and __ne__ from:
  226. /// 1. IStructuralEquatable.Equals
  227. /// 2. IValueEquality.Equals (CLR2 only)
  228. /// </summary>
  229. class EqualityResolver : MemberResolver {
  230. public static readonly EqualityResolver Instance = new EqualityResolver();
  231. private EqualityResolver() { }
  232. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  233. Assert.NotNull(binder, action, type, name);
  234. bool equality;
  235. switch (name) {
  236. case "__eq__": equality = true; break;
  237. case "__ne__": equality = false; break;
  238. default:
  239. return MemberGroup.EmptyGroup;
  240. }
  241. if (typeof(IStructuralEquatable).IsAssignableFrom(type)) {
  242. return new MemberGroup(
  243. GetEqualityMethods(type, equality ? "StructuralEqualityMethod" : "StructuralInequalityMethod")
  244. );
  245. #if CLR2
  246. } else if (typeof(IValueEquality).IsAssignableFrom(type)) {
  247. return new MemberGroup(
  248. GetEqualityMethods(type, equality ? "ValueEqualsMethod" : "ValueNotEqualsMethod")
  249. );
  250. #endif
  251. }
  252. return MemberGroup.EmptyGroup;
  253. }
  254. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  255. yield return "__eq__";
  256. yield return "__ne__";
  257. }
  258. }
  259. /// <summary>
  260. /// Resolves methods mapped to __gt__, __lt__, __ge__, __le__, as well as providing an alternate resolution
  261. /// for __eq__ and __ne__, from the comparable type's CompareTo method.
  262. ///
  263. /// This should be run after the EqualityResolver.
  264. /// </summary>
  265. class ComparisonResolver : MemberResolver {
  266. private readonly bool _excludePrimitiveTypes;
  267. private readonly Type/*!*/ _comparable;
  268. private readonly Dictionary<string/*!*/, string/*!*/>/*!*/ _helperMap;
  269. public ComparisonResolver(Type/*!*/ comparable, string/*!*/ helperPrefix) {
  270. Assert.NotNull(comparable, helperPrefix);
  271. _excludePrimitiveTypes = comparable == typeof(IComparable);
  272. _comparable = comparable;
  273. _helperMap = new Dictionary<string, string>();
  274. _helperMap["__eq__"] = helperPrefix + "Equality";
  275. _helperMap["__ne__"] = helperPrefix + "Inequality";
  276. _helperMap["__gt__"] = helperPrefix + "GreaterThan";
  277. _helperMap["__lt__"] = helperPrefix + "LessThan";
  278. _helperMap["__ge__"] = helperPrefix + "GreaterEqual";
  279. _helperMap["__le__"] = helperPrefix + "LessEqual";
  280. }
  281. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  282. Assert.NotNull(binder, action, type, name);
  283. // Do not map IComparable if this is a primitive builtin type.
  284. if (_excludePrimitiveTypes) {
  285. if (type.IsPrimitive || type == typeof(BigInteger) ||
  286. type == typeof(string) || type == typeof(decimal)) {
  287. return MemberGroup.EmptyGroup;
  288. }
  289. }
  290. string helperName;
  291. if (_helperMap.TryGetValue(name, out helperName) &&
  292. _comparable.IsAssignableFrom(type)) {
  293. return new MemberGroup(GetEqualityMethods(type, helperName));
  294. }
  295. return MemberGroup.EmptyGroup;
  296. }
  297. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  298. return _helperMap.Keys;
  299. }
  300. }
  301. /// <summary>
  302. /// Resolves methods mapped to __*__ methods automatically from the .NET operator.
  303. /// </summary>
  304. class OperatorResolver : MemberResolver {
  305. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  306. if (type.IsSealed() && type.IsAbstract()) {
  307. // static types don't have PythonOperationKind
  308. return MemberGroup.EmptyGroup;
  309. }
  310. // try mapping __*__ methods to .NET method names
  311. PythonOperationKind opMap;
  312. EnsureOperatorTable();
  313. if (_pythonOperatorTable.TryGetValue(name, out opMap)) {
  314. if (IncludeOperatorMethod(type, opMap)) {
  315. OperatorMapping opInfo;
  316. if (IsReverseOperator(opMap)) {
  317. opInfo = OperatorMapping.GetOperatorMapping(opMap & ~PythonOperationKind.Reversed);
  318. } else {
  319. opInfo = OperatorMapping.GetOperatorMapping(opMap);
  320. }
  321. if (opInfo != null) {
  322. foreach (Type curType in binder.GetContributingTypes(type)) {
  323. #if !CLR2
  324. if (curType == typeof(double)) {
  325. if ((opInfo.Operator & PythonOperationKind.Comparison) != 0) {
  326. // we override these with our own comparisons in DoubleOps
  327. continue;
  328. }
  329. } else
  330. #endif
  331. if (curType == typeof(BigInteger)) {
  332. if (opInfo.Operator == PythonOperationKind.Mod ||
  333. opInfo.Operator == PythonOperationKind.RightShift ||
  334. opInfo.Operator == PythonOperationKind.LeftShift ||
  335. opInfo.Operator == PythonOperationKind.Compare ||
  336. opInfo.Operator == PythonOperationKind.Divide) {
  337. // we override these with our own modulus/power PythonOperationKind which are different from BigInteger.
  338. continue;
  339. }
  340. #if !CLR2
  341. } else if (curType == typeof(Complex) && opInfo.Operator == PythonOperationKind.Divide) {
  342. // we override this with our own division PythonOperationKind which is different from .NET Complex.
  343. continue;
  344. #endif
  345. }
  346. Debug.Assert(opInfo.Name != "Equals");
  347. MemberGroup res = binder.GetMember(curType, opInfo.Name);
  348. if (res.Count == 0 && opInfo.AlternateName != null) {
  349. res = binder.GetMember(curType, opInfo.AlternateName);
  350. if (opInfo.AlternateName == "Equals") {
  351. // "Equals" is available as an alternate method name. Because it's also on object and Python
  352. // doesn't define it on object we need to filter it out.
  353. res = FilterObjectEquality(res);
  354. }
  355. res = FilterAlternateMethods(opInfo, res);
  356. }
  357. if (res.Count > 0) {
  358. return FilterForwardReverseMethods(name, res, type, opMap);
  359. }
  360. }
  361. }
  362. }
  363. }
  364. if (name == "__call__") {
  365. MemberGroup res = binder.GetMember(type, "Call");
  366. if (res.Count > 0) {
  367. return res;
  368. }
  369. }
  370. return MemberGroup.EmptyGroup;
  371. }
  372. /// <summary>
  373. /// Filters alternative methods out that don't match the expected signature and therefore
  374. /// are just sharing a common method name.
  375. /// </summary>
  376. private static MemberGroup FilterAlternateMethods(OperatorMapping opInfo, MemberGroup res) {
  377. if (res.Count > 0 && opInfo.AlternateExpectedType != null) {
  378. List<MemberTracker> matchingMethods = new List<MemberTracker>();
  379. for (int i = 0; i < res.Count; i++) {
  380. MemberTracker mt = res[i];
  381. if (mt.MemberType == TrackerTypes.Method &&
  382. ((MethodTracker)mt).Method.ReturnType == opInfo.AlternateExpectedType) {
  383. matchingMethods.Add(mt);
  384. }
  385. }
  386. if (matchingMethods.Count == 0) {
  387. res = MemberGroup.EmptyGroup;
  388. } else {
  389. res = new MemberGroup(matchingMethods.ToArray());
  390. }
  391. }
  392. return res;
  393. }
  394. /// <summary>
  395. /// Removes Object.Equals methods as we never return these for PythonOperationKind.
  396. /// </summary>
  397. private static MemberGroup/*!*/ FilterObjectEquality(MemberGroup/*!*/ group) {
  398. List<MemberTracker> res = null;
  399. for (int i = 0; i < group.Count; i++) {
  400. MemberTracker mt = group[i];
  401. if (mt.MemberType == TrackerTypes.Method && (mt.DeclaringType == typeof(object) || mt.DeclaringType == typeof(double) || mt.DeclaringType == typeof(float)) && mt.Name == "Equals") {
  402. if (res == null) {
  403. res = new List<MemberTracker>();
  404. for (int j = 0; j < i; j++) {
  405. res.Add(group[j]);
  406. }
  407. }
  408. } else if (mt.MemberType == TrackerTypes.Method && mt.DeclaringType == typeof(ValueType) && mt.Name == "Equals") {
  409. // ValueType.Equals overrides object.Equals but we can't call it w/ a boxed value type therefore
  410. // we return the object version and the virtual call will dispatch to ValueType.Equals.
  411. if (res == null) {
  412. res = new List<MemberTracker>();
  413. for (int j = 0; j < i; j++) {
  414. res.Add(group[j]);
  415. }
  416. }
  417. res.Add(MemberTracker.FromMemberInfo(typeof(object).GetMethod("Equals", new Type[] { typeof(object) })));
  418. } else if (res != null) {
  419. res.Add(group[i]);
  420. }
  421. }
  422. if (res != null) {
  423. if (res.Count == 0) {
  424. return MemberGroup.EmptyGroup;
  425. }
  426. return new MemberGroup(res.ToArray());
  427. }
  428. return group;
  429. }
  430. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  431. EnsureOperatorTable();
  432. foreach (string si in _pythonOperatorTable.Keys) {
  433. yield return si;
  434. }
  435. yield return "__call__";
  436. }
  437. }
  438. /// <summary>
  439. /// Provides bindings to private members when that global option is enabled.
  440. /// </summary>
  441. class PrivateBindingResolver : MemberResolver {
  442. private const BindingFlags _privateFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
  443. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  444. if (binder.DomainManager.Configuration.PrivateBinding) {
  445. // in private binding mode Python exposes private members under a mangled name.
  446. string header = "_" + type.Name + "__";
  447. if (name.StartsWith(header)) {
  448. string memberName = name.Substring(header.Length);
  449. MemberGroup res = new MemberGroup(type.GetMember(memberName, _privateFlags));
  450. if (res.Count > 0) {
  451. return FilterFieldAndEvent(res);
  452. }
  453. res = new MemberGroup(type.GetMember(memberName, BindingFlags.FlattenHierarchy | _privateFlags));
  454. if (res.Count > 0) {
  455. return FilterFieldAndEvent(res);
  456. }
  457. }
  458. }
  459. return MemberGroup.EmptyGroup;
  460. }
  461. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  462. if (!binder.DomainManager.Configuration.PrivateBinding) {
  463. yield break;
  464. }
  465. foreach (MemberInfo mi in type.GetMembers(_privateFlags | BindingFlags.FlattenHierarchy)) {
  466. yield return String.Concat("_", mi.DeclaringType.Name, "__", mi.Name);
  467. }
  468. }
  469. }
  470. /// <summary>
  471. /// Provides resolutions for protected members that haven't yet been
  472. /// subclassed by NewTypeMaker.
  473. /// </summary>
  474. class ProtectedMemberResolver : MemberResolver {
  475. public override MemberGroup/*!*/ ResolveMember(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type, string/*!*/ name) {
  476. foreach (Type t in binder.GetContributingTypes(type)) {
  477. MemberGroup res = new MemberGroup(
  478. t.GetMember(name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
  479. .Where(ProtectedOnly)
  480. .ToArray());
  481. for (int i = 0; i < res.Count; i++) {
  482. MethodTracker meth = res[i] as MethodTracker;
  483. if (meth == null) {
  484. continue;
  485. }
  486. if (meth.Name == "Finalize" && meth.Method.GetBaseDefinition() == typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)) {
  487. MemberTracker[] retained = new MemberTracker[res.Count - 1];
  488. if (res.Count == 1) {
  489. res = MemberGroup.EmptyGroup;
  490. } else {
  491. for (int j = 0; j < i; j++) {
  492. retained[j] = res[j];
  493. }
  494. for (int j = i + 1; j < res.Count; j++) {
  495. retained[j - 1] = res[j];
  496. }
  497. res = new MemberGroup(retained);
  498. }
  499. break;
  500. }
  501. }
  502. return FilterSpecialNames(res, name, action);
  503. }
  504. return MemberGroup.EmptyGroup;
  505. }
  506. protected override IEnumerable<string/*!*/>/*!*/ GetCandidateNames(MemberBinder/*!*/ binder, MemberRequestKind/*!*/ action, Type/*!*/ type) {
  507. // these members are visible but only accept derived types.
  508. foreach (Type t in binder.GetContributingTypes(type)) {
  509. foreach (MemberInfo mi in t.GetMembers(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) {
  510. if (ProtectedOnly(mi)) {
  511. yield return mi.Name;
  512. }
  513. }
  514. }
  515. }
  516. }
  517. /// <summary>
  518. /// Creates the resolver table which includes all the possible resolutions.
  519. /// </summary>
  520. /// <returns></returns>
  521. private static MemberResolver/*!*/[]/*!*/ MakeResolverTable() {
  522. return new MemberResolver[] {
  523. // values that live on object need to run before the StandardResolver
  524. // which will pick up values off of object.
  525. new OneOffResolver("__str__", StringResolver),
  526. new OneOffResolver("__new__", NewResolver),
  527. new OneOffResolver("__repr__", ReprResolver),
  528. new OneOffResolver("__hash__", HashResolver),
  529. new OneOffResolver("__iter__", IterResolver),
  530. #if FEATURE_SERIALIZATION
  531. new OneOffResolver("__reduce_ex__", SerializationResolver),
  532. #endif
  533. // The standard resolver looks for types using .NET reflection by name
  534. new StandardResolver(),
  535. // Runs after StandardResolver so custom __eq__ methods can be added
  536. // that support things like returning NotImplemented vs. IValueEquality
  537. // which only supports true/false. Runs before OperatorResolver so that
  538. // IStructuralEquatable and IValueEquality take precedence over Equals,
  539. // which can be provided for nice .NET interop.
  540. EqualityResolver.Instance,
  541. new ComparisonResolver(typeof(IStructuralComparable), "StructuralComparable"),
  542. new OneOffResolver("__all__", AllResolver),
  543. new OneOffResolver("__contains__", ContainsResolver),
  544. new OneOffResolver("__dir__", DirResolver),
  545. new OneOffResolver("__doc__", DocResolver),
  546. new OneOffResolver("__enter__", EnterResolver),
  547. new OneOffResolver("__exit__", ExitResolver),
  548. new OneOffResolver("__len__", LengthResolver),
  549. new OneOffResolver("__format__", FormatResolver),
  550. new OneOffResolver("next", NextResolver),
  551. new OneOffResolver("__complex__", ComplexResolver),
  552. new OneOffResolver("__float__", FloatResolver),
  553. new OneOffResolver("__int__", IntResolver),
  554. new OneOffResolver("__long__", BigIntegerResolver),
  555. // non standard PythonOperationKind which are Python specific
  556. new OneOffResolver("__truediv__", new OneOffOperatorBinder("TrueDivide", "__truediv__", PythonOperationKind.TrueDivide).Resolver),
  557. new OneOffResolver("__rtruediv__", new OneOffOperatorBinder("TrueDivide", "__rtruediv__", PythonOperationKind.ReverseTrueDivide).Resolver),
  558. new OneOffResolver("__itruediv__", new OneOffOperatorBinder("InPlaceTrueDivide", "__itruediv__", PythonOperationKind.InPlaceTrueDivide).Resolver),
  559. new OneOffResolver("__floordiv__", new OneOffOperatorBinder("FloorDivide", "__floordiv__", PythonOperationKind.FloorDivide).Resolver),
  560. new OneOffResolver("__rfloordiv__", new OneOffOperatorBinder("FloorDivide", "__rfloordiv__", PythonOperationKind.ReverseFloorDivide).Resolver),
  561. new OneOffResolver("__ifloordiv__", new OneOffOperatorBinder("InPlaceFloorDivide", "__ifloordiv__", PythonOperationKind.InPlaceFloorDivide).Resolver),
  562. new OneOffResolver("__pow__", new OneOffPowerBinder("__pow__", PythonOperationKind.Power).Resolver),
  563. new OneOffResolver("__rpow__", new OneOffPowerBinder("__rpow__", PythonOperationKind.ReversePower).Resolver),
  564. new OneOffResolver("__ipow__", new OneOffOperatorBinder("InPlacePower", "__ipow__", PythonOperationKind.InPlacePower).Resolver),
  565. new OneOffResolver("__abs__", new OneOffOperatorBinder("Abs", "__abs__", PythonOperationKind.AbsoluteValue).Resolver),
  566. new OneOffResolver("__divmod__", new OneOffOperatorBinder("DivMod", "__divmod__", PythonOperationKind.DivMod).Resolver),
  567. new OneOffResolver("__rdivmod__", new OneOffOperatorBinder("DivMod", "__rdivmod__", PythonOperationKind.DivMod).Resolver),
  568. // The operator resolver maps standard .NET operator methods into Python operator
  569. // methods
  570. new OperatorResolver(),
  571. // Runs after operator resolver to map default members to __getitem__/__setitem__
  572. new OneOffResolver("__getitem__", GetItemResolver),
  573. new OneOffResolver("__setitem__", SetItemResolver),
  574. // Runs after operator resolver to map __ne__ -> !__eq__
  575. new OneOffResolver("__ne__", FallbackInequalityResolver),
  576. // Runs after the operator resolver to map IComparable
  577. new ComparisonResolver(typeof(IComparable), "Comparable"),
  578. // Protected members are visible but only usable from derived types
  579. new ProtectedMemberResolver(),
  580. // Support binding to private members if the user has enabled that feature
  581. new PrivateBindingResolver(),
  582. };
  583. }
  584. #endregion
  585. #region One-off resolvers
  586. #region Resolving numerical conversions (__complex__, __float__, __int__, and __long__)
  587. /// <summary>
  588. /// Provides a resolution for __complex__
  589. /// </summary>
  590. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ ComplexResolver {
  591. get {
  592. if (_ComplexResolver != null) return _ComplexResolver;
  593. _ComplexResolver = MakeConversionResolver(new List<Type> {
  594. typeof(Complex), typeof(ExtensibleComplex), typeof(Extensible<Complex>),
  595. typeof(double), typeof(Extensible<double>)
  596. });
  597. return _ComplexResolver;
  598. }
  599. }
  600. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _ComplexResolver;
  601. /// <summary>
  602. /// Provides a resolution for __float__
  603. /// </summary>
  604. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ FloatResolver {
  605. get {
  606. if (_FloatResolver != null) return _FloatResolver;
  607. _FloatResolver = MakeConversionResolver(new List<Type> {
  608. typeof(double), typeof(Extensible<double>)
  609. });
  610. return _FloatResolver;
  611. }
  612. }
  613. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _FloatResolver;
  614. /// <summary>
  615. /// Provides a resolution for __int__
  616. /// </summary>
  617. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ IntResolver {
  618. get {
  619. if (_IntResolver != null) return _IntResolver;
  620. _IntResolver = MakeConversionResolver(new List<Type> {
  621. typeof(int), typeof(Extensible<int>),
  622. typeof(BigInteger), typeof(Extensible<BigInteger>)
  623. });
  624. return _IntResolver;
  625. }
  626. }
  627. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _IntResolver;
  628. /// <summary>
  629. /// Provides a resolution for __long__
  630. /// </summary>
  631. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ BigIntegerResolver {
  632. get {
  633. if (_BigIntegerResolver != null) return _BigIntegerResolver;
  634. _BigIntegerResolver = MakeConversionResolver(new List<Type> {
  635. typeof(BigInteger), typeof(Extensible<BigInteger>),
  636. typeof(int), typeof(Extensible<int>)
  637. });
  638. return _BigIntegerResolver;
  639. }
  640. }
  641. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _BigIntegerResolver;
  642. /// <summary>
  643. /// Provides a resolution for __getitem__
  644. /// </summary>
  645. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ GetItemResolver {
  646. get {
  647. if (_GetItemResolver == null) {
  648. _GetItemResolver = MakeIndexerResolver(false);
  649. }
  650. return _GetItemResolver;
  651. }
  652. }
  653. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _GetItemResolver;
  654. /// <summary>
  655. /// Provides a resolution for __setitem__
  656. /// </summary>
  657. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/>/*!*/ SetItemResolver {
  658. get {
  659. if (_SetItemResolver == null) {
  660. _SetItemResolver = MakeIndexerResolver(true);
  661. }
  662. return _SetItemResolver;
  663. }
  664. }
  665. private static Func<MemberBinder/*!*/, Type/*!*/, MemberGroup/*!*/> _SetItemResolver;
  666. #endregion
  667. /// <summary>
  668. /// Provides a resolution for __str__.
  669. /// </summary>
  670. private static MemberGroup/*!*/ StringResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  671. if (type != typeof(double) && type != typeof(float)
  672. #if FEATURE_NUMERICS
  673. && type != typeof(Complex)
  674. #endif
  675. ) {
  676. MethodInfo tostr = type.GetMethod("ToString", ReflectionUtils.EmptyTypes);
  677. if (tostr != null && tostr.DeclaringType != typeof(object)) {
  678. return GetInstanceOpsMethod(type, "ToStringMethod");
  679. }
  680. }
  681. return MemberGroup.EmptyGroup;
  682. }
  683. /// <summary>
  684. /// Provides a resolution for __repr__
  685. /// </summary>
  686. private static MemberGroup/*!*/ ReprResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  687. // __repr__ for normal .NET types is special, if we're a Python type then
  688. // we'll use one of the built-in reprs (from object or from the type)
  689. if (!PythonBinder.IsPythonType(type) &&
  690. (!type.IsSealed() || !type.IsAbstract())) { // static types don't get __repr__
  691. // check and see if __repr__ has been overridden by the base type.
  692. foreach (Type t in binder.GetContributingTypes(type)) {
  693. if (t == typeof(ObjectOps) && type != typeof(object)) {
  694. break;
  695. }
  696. if (t.GetMember("__repr__").Length > 0) {
  697. // type has a specific __repr__ overload, pick it up normally later
  698. return MemberGroup.EmptyGroup;
  699. }
  700. }
  701. // no override, pick up the default fancy .NET __repr__
  702. return binder.GetBaseInstanceMethod(type, "FancyRepr");
  703. }
  704. return MemberGroup.EmptyGroup;
  705. }
  706. #if FEATURE_SERIALIZATION
  707. private static MemberGroup/*!*/ SerializationResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  708. if (type.IsSerializable && !PythonBinder.IsPythonType(type)) {
  709. string methodName = "__reduce_ex__";
  710. if (!TypeOverridesMethod(binder, type, methodName)) {
  711. return GetInstanceOpsMethod(type, "SerializeReduce");
  712. }
  713. }
  714. return MemberGroup.EmptyGroup;
  715. }
  716. #endif
  717. #if !SILVERLIGHT
  718. /// <summary>
  719. /// Helper to see if the type explicitly overrides the method. This ignores members
  720. /// defined on object.
  721. /// </summary>
  722. private static bool TypeOverridesMethod(MemberBinder/*!*/ binder, Type/*!*/ type, string/*!*/ methodName) {
  723. // check and see if the method has been overridden by the base type.
  724. foreach (Type t in binder.GetContributingTypes(type)) {
  725. if (!PythonBinder.IsPythonType(type) && t == typeof(ObjectOps) && type != typeof(object)) {
  726. break;
  727. }
  728. MemberInfo[] reduce = t.GetMember(methodName);
  729. if (reduce.Length > 0) {
  730. // type has a specific overload
  731. return true;
  732. }
  733. }
  734. return false;
  735. }
  736. #endif
  737. /// <summary>
  738. /// Provides a resolution for __hash__, first looking for IStructuralEquatable.GetHashCode,
  739. /// then IValueEquality.GetValueHashCode.
  740. /// </summary>
  741. private static MemberGroup/*!*/ HashResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  742. #if FEATURE_VALUE_EQUALITY
  743. if (typeof(IStructuralEquatable).IsAssignableFrom(type) && !type.IsInterface) {
  744. #else
  745. if ((typeof(IStructuralEquatable).IsAssignableFrom(type) ||
  746. typeof(IValueEquality).IsAssignableFrom(type)) && !type.IsInterface) {
  747. #endif
  748. // check and see if __hash__ has been overridden by the base type.
  749. foreach (Type t in binder.GetContributingTypes(type)) {
  750. // if it's defined on object, it's not overridden
  751. if (t == typeof(ObjectOps) || t == typeof(object)) {
  752. break;
  753. }
  754. MemberInfo[] hash = t.GetMember("__hash__");
  755. if (hash.Length > 0) {
  756. return MemberGroup.EmptyGroup;
  757. }
  758. }
  759. #if FEATURE_VALUE_EQUALITY
  760. return GetInstanceOpsMethod(type, "StructuralHashMethod");
  761. #else
  762. if (typeof(IStructuralEquatable).IsAssignableFrom(type)) {
  763. return GetInstanceOpsMethod(type, "StructuralHashMethod");
  764. }
  765. if (typeof(IValueEquality).IsAssignableFrom(type)) {
  766. return new MemberGroup(typeof(IValueEquality).GetMethod("GetValueHashCode"));
  767. }
  768. #endif
  769. }
  770. // otherwise we'll pick up __hash__ from ObjectOps which will call .NET's .GetHashCode therefore
  771. // we don't explicitly search to see if the object overrides GetHashCode here.
  772. return MemberGroup.EmptyGroup;
  773. }
  774. /// <summary>
  775. /// Provides a resolution for __new__. For standard .NET types __new__ resolves to their
  776. /// constructor. For Python types they inherit __new__ from their base class.
  777. ///
  778. /// TODO: Can we just always fallback to object.__new__? If not why not?
  779. /// </summary>
  780. private static MemberGroup/*!*/ NewResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  781. if (type.IsSealed && type.IsAbstract) {
  782. // static types don't have __new__
  783. return MemberGroup.EmptyGroup;
  784. }
  785. bool isPythonType = typeof(IPythonObject).IsAssignableFrom(type);
  786. // check and see if __new__ has been overridden by the base type.
  787. foreach (Type t in binder.GetContributingTypes(type)) {
  788. if (!isPythonType && t == typeof(ObjectOps) && type != typeof(object)) {
  789. break;
  790. }
  791. MemberInfo[] news = t.GetMember("__new__");
  792. if (news.Length > 0) {
  793. // type has a specific __new__ overload, return that for the constructor
  794. return GetExtensionMemberGroup(type, news);
  795. }
  796. }
  797. // TODO: CompilerHelpers.GetConstructors(type, binder.DomainManager.Configuration.PrivateBinding, true);
  798. var ctors = CompilerHelpers.FilterConstructorsToPublicAndProtected(
  799. type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  800. ).ToArray();
  801. // type has no Python __new__, just return the .NET constructors if they have
  802. // a custom new
  803. if (!PythonTypeOps.IsDefaultNew(ctors)) {
  804. return new MemberGroup(ctors);
  805. }
  806. // if no ctor w/ parameters are defined, fall back to object.__new__ which
  807. // will ignore all the extra arguments allowing the user to just override
  808. // __init__.
  809. return MemberGroup.EmptyGroup;
  810. }
  811. internal static MemberGroup GetExtensionMemberGroup(Type type, MemberInfo[] news) {
  812. List<MemberTracker> mts = new List<MemberTracker>();
  813. foreach (MemberInfo mi in news) {
  814. if (mi.MemberType == MemberTypes.Method) {
  815. if (mi.DeclaringType.IsAssignableFrom(type)) {
  816. mts.Add(MethodTracker.FromMemberInfo(mi));
  817. } else {
  818. mts.Add(MethodTracker.FromMemberInfo(mi, type));
  819. }
  820. }
  821. }
  822. return new MemberGroup(mts.ToArray());
  823. }
  824. /// <summary>
  825. /// Provides a resolution for next
  826. /// </summary>
  827. private static MemberGroup/*!*/ NextResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  828. if (typeof(IEnumerator).IsAssignableFrom(type)) {
  829. return GetInstanceOpsMethod(type, "NextMethod");
  830. }
  831. return MemberGroup.EmptyGroup;
  832. }
  833. /// <summary>
  834. /// Provides a resolution for __len__
  835. /// </summary>
  836. private static MemberGroup/*!*/ LengthResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  837. if (!type.IsDefined(typeof(DontMapICollectionToLenAttribute), true)) {
  838. if (binder.GetInterfaces(type).Contains(typeof(ICollection))) {
  839. return GetInstanceOpsMethod(type, "LengthMethod");
  840. }
  841. foreach (Type t in binder.GetInterfaces(type)) {
  842. if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(ICollection<>)) {
  843. MethodInfo genMeth = typeof(InstanceOps).GetMethod("GenericLengthMethod");
  844. return new MemberGroup(
  845. MethodTracker.FromMemberInfo(genMeth.MakeGenericMethod(t.GetGenericArguments()), type)
  846. );
  847. }
  848. }
  849. }
  850. return MemberGroup.EmptyGroup;
  851. }
  852. /// <summary>
  853. /// Provides a resolution for __iter__
  854. /// </summary>
  855. private static MemberGroup/*!*/ IterResolver(MemberBinder/*!*/ binder, Type/*!*/ type) {
  856. if (type == typeof(string)) {
  857. // __iter__ is only exposed in 3.0
  858. if (binder.Binder.Context.PythonOptions.Python30) {
  859. return GetInstanceOpsMethod(type, "IterMethodForString");
  860. }
  861. return MemberGroup.EmptyGroup;
  862. }
  863. if (typeof(Bytes).IsAssignableFrom(type)) {
  864. // __iter__ is only exposed in 3.0
  865. if (binder.Binder.Context.PythonOptions.Python30) {
  866. return GetInstanceOpsMethod(type, "IterMethodForBytes");
  867. }
  868. return MemberGroup.EmptyGroup;
  869. }
  870. foreach (Type t in binder.GetContributingTypes(type)) {
  871. MemberInfo[] news = t.GetMember("__iter__");
  872. if (news.Length > 0) {
  873. // type has a specific __iter__ overload, we'll pick it up later
  874. return MemberGroup.EmptyGroup;
  875. }
  876. }
  877. if (!type.IsDefined(typeof(DontMapIEnumerableToIterAttribute), true)) {
  878. // no special __iter__, use the default.
  879. if (typeof

Large files files are truncated, but you can click here to view the full file