/Languages/IronPython/IronPython/Runtime/Binding/PythonBinder.cs

http://github.com/IronLanguages/main · C# · 1107 lines · 816 code · 173 blank · 118 comment · 165 complexity · fa60eb57fdb4d70f99fda8c26c2a5219 MD5 · raw file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. using System.Numerics;
  18. #else
  19. using Microsoft.Scripting.Ast;
  20. using Microsoft.Scripting.Math;
  21. using Complex = Microsoft.Scripting.Math.Complex64;
  22. #endif
  23. using System;
  24. using System.Collections;
  25. using System.Collections.Generic;
  26. using System.Diagnostics;
  27. using System.Dynamic;
  28. using System.Linq;
  29. using System.Reflection;
  30. using System.Threading;
  31. using Microsoft.Scripting;
  32. using Microsoft.Scripting.Actions;
  33. using Microsoft.Scripting.Actions.Calls;
  34. using Microsoft.Scripting.Generation;
  35. using Microsoft.Scripting.Runtime;
  36. using Microsoft.Scripting.Utils;
  37. using IronPython.Runtime.Exceptions;
  38. using IronPython.Runtime.Operations;
  39. using IronPython.Runtime.Types;
  40. namespace IronPython.Runtime.Binding {
  41. using Ast = Expression;
  42. using AstUtils = Microsoft.Scripting.Ast.Utils;
  43. partial class PythonBinder : DefaultBinder {
  44. private PythonContext/*!*/ _context;
  45. private SlotCache/*!*/ _typeMembers = new SlotCache();
  46. private SlotCache/*!*/ _resolvedMembers = new SlotCache();
  47. private Dictionary<Type/*!*/, IList<Type/*!*/>/*!*/>/*!*/ _dlrExtensionTypes;
  48. private bool _registeredInterfaceExtensions; // true if someone has registered extensions for interfaces
  49. [MultiRuntimeAware]
  50. private static readonly Dictionary<Type/*!*/, ExtensionTypeInfo/*!*/>/*!*/ _sysTypes = MakeSystemTypes();
  51. public PythonBinder(PythonContext/*!*/ pythonContext, CodeContext context) {
  52. ContractUtils.RequiresNotNull(pythonContext, "pythonContext");
  53. _dlrExtensionTypes = MakeExtensionTypes();
  54. _context = pythonContext;
  55. if (context != null) {
  56. context.LanguageContext.DomainManager.AssemblyLoaded += new EventHandler<AssemblyLoadedEventArgs>(DomainManager_AssemblyLoaded);
  57. foreach (Assembly asm in pythonContext.DomainManager.GetLoadedAssemblyList()) {
  58. DomainManager_AssemblyLoaded(this, new AssemblyLoadedEventArgs(asm));
  59. }
  60. }
  61. }
  62. public PythonBinder(PythonBinder binder) {
  63. _context = binder._context;
  64. _typeMembers = binder._typeMembers;
  65. _resolvedMembers = binder._resolvedMembers;
  66. _dlrExtensionTypes = binder._dlrExtensionTypes;
  67. _registeredInterfaceExtensions = binder._registeredInterfaceExtensions;
  68. }
  69. public override Expression/*!*/ ConvertExpression(Expression/*!*/ expr, Type/*!*/ toType, ConversionResultKind kind, OverloadResolverFactory factory) {
  70. ContractUtils.RequiresNotNull(expr, "expr");
  71. ContractUtils.RequiresNotNull(toType, "toType");
  72. Type exprType = expr.Type;
  73. if (toType == typeof(object)) {
  74. if (exprType.IsValueType()) {
  75. return AstUtils.Convert(expr, toType);
  76. } else {
  77. return expr;
  78. }
  79. }
  80. if (toType.IsAssignableFrom(exprType)) {
  81. return expr;
  82. }
  83. Type visType = Context.Binder.PrivateBinding ? toType : CompilerHelpers.GetVisibleType(toType);
  84. if (exprType == typeof(PythonType) && visType == typeof(Type)) {
  85. return AstUtils.Convert(expr, visType); // use the implicit conversion
  86. }
  87. return Binders.Convert(
  88. ((PythonOverloadResolverFactory)factory)._codeContext,
  89. _context,
  90. visType,
  91. visType == typeof(char) ? ConversionResultKind.ImplicitCast : kind,
  92. expr
  93. );
  94. }
  95. internal static MethodInfo GetGenericConvertMethod(Type toType) {
  96. if (toType.IsValueType()) {
  97. if (toType.IsGenericType() && toType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
  98. return typeof(Converter).GetMethod("ConvertToNullableType");
  99. } else {
  100. return typeof(Converter).GetMethod("ConvertToValueType");
  101. }
  102. } else {
  103. return typeof(Converter).GetMethod("ConvertToReferenceType");
  104. }
  105. }
  106. internal static MethodInfo GetFastConvertMethod(Type toType) {
  107. if (toType == typeof(char)) {
  108. return typeof(Converter).GetMethod("ConvertToChar");
  109. } else if (toType == typeof(int)) {
  110. return typeof(Converter).GetMethod("ConvertToInt32");
  111. } else if (toType == typeof(string)) {
  112. return typeof(Converter).GetMethod("ConvertToString");
  113. } else if (toType == typeof(long)) {
  114. return typeof(Converter).GetMethod("ConvertToInt64");
  115. } else if (toType == typeof(double)) {
  116. return typeof(Converter).GetMethod("ConvertToDouble");
  117. } else if (toType == typeof(bool)) {
  118. return typeof(Converter).GetMethod("ConvertToBoolean");
  119. } else if (toType == typeof(BigInteger)) {
  120. return typeof(Converter).GetMethod("ConvertToBigInteger");
  121. } else if (toType == typeof(Complex)) {
  122. return typeof(Converter).GetMethod("ConvertToComplex");
  123. } else if (toType == typeof(IEnumerable)) {
  124. return typeof(Converter).GetMethod("ConvertToIEnumerable");
  125. } else if (toType == typeof(float)) {
  126. return typeof(Converter).GetMethod("ConvertToSingle");
  127. } else if (toType == typeof(byte)) {
  128. return typeof(Converter).GetMethod("ConvertToByte");
  129. } else if (toType == typeof(sbyte)) {
  130. return typeof(Converter).GetMethod("ConvertToSByte");
  131. } else if (toType == typeof(short)) {
  132. return typeof(Converter).GetMethod("ConvertToInt16");
  133. } else if (toType == typeof(uint)) {
  134. return typeof(Converter).GetMethod("ConvertToUInt32");
  135. } else if (toType == typeof(ulong)) {
  136. return typeof(Converter).GetMethod("ConvertToUInt64");
  137. } else if (toType == typeof(ushort)) {
  138. return typeof(Converter).GetMethod("ConvertToUInt16");
  139. } else if (toType == typeof(Type)) {
  140. return typeof(Converter).GetMethod("ConvertToType");
  141. } else {
  142. return null;
  143. }
  144. }
  145. public override object Convert(object obj, Type toType) {
  146. return Converter.Convert(obj, toType);
  147. }
  148. public override bool CanConvertFrom(Type fromType, Type toType, bool toNotNullable, NarrowingLevel level) {
  149. return Converter.CanConvertFrom(fromType, toType, level);
  150. }
  151. public override Candidate PreferConvert(Type t1, Type t2) {
  152. return Converter.PreferConvert(t1, t2);
  153. }
  154. public override bool PrivateBinding {
  155. get {
  156. return _context.DomainManager.Configuration.PrivateBinding;
  157. }
  158. }
  159. public override ErrorInfo MakeSetValueTypeFieldError(FieldTracker field, DynamicMetaObject instance, DynamicMetaObject value) {
  160. // allow the set but emit a warning
  161. return ErrorInfo.FromValueNoError(
  162. Expression.Block(
  163. Expression.Call(
  164. typeof(PythonOps).GetMethod("Warn"),
  165. Expression.Constant(_context.SharedContext),
  166. Expression.Constant(PythonExceptions.RuntimeWarning),
  167. Expression.Constant(ReflectedField.UpdateValueTypeFieldWarning),
  168. Expression.Constant(
  169. new object[] { field.Name, field.DeclaringType.Name }
  170. )
  171. ),
  172. Expression.Assign(
  173. Expression.Field(
  174. AstUtils.Convert(
  175. instance.Expression,
  176. field.DeclaringType
  177. ),
  178. field.Field
  179. ),
  180. ConvertExpression(
  181. value.Expression,
  182. field.FieldType,
  183. ConversionResultKind.ExplicitCast,
  184. new PythonOverloadResolverFactory(
  185. this,
  186. Expression.Constant(_context.SharedContext)
  187. )
  188. )
  189. )
  190. )
  191. );
  192. }
  193. public override ErrorInfo MakeConversionError(Type toType, Expression value) {
  194. return ErrorInfo.FromException(
  195. Ast.Call(
  196. typeof(PythonOps).GetMethod("TypeErrorForTypeMismatch"),
  197. AstUtils.Constant(DynamicHelpers.GetPythonTypeFromType(toType).Name),
  198. AstUtils.Convert(value, typeof(object))
  199. )
  200. );
  201. }
  202. public override ErrorInfo/*!*/ MakeNonPublicMemberGetError(OverloadResolverFactory resolverFactory, MemberTracker member, Type type, DynamicMetaObject instance) {
  203. if (PrivateBinding) {
  204. return base.MakeNonPublicMemberGetError(resolverFactory, member, type, instance);
  205. }
  206. return ErrorInfo.FromValue(
  207. BindingHelpers.TypeErrorForProtectedMember(type, member.Name)
  208. );
  209. }
  210. public override ErrorInfo/*!*/ MakeStaticAssignFromDerivedTypeError(Type accessingType, DynamicMetaObject instance, MemberTracker info, DynamicMetaObject assignedValue, OverloadResolverFactory factory) {
  211. return MakeMissingMemberError(accessingType, instance, info.Name);
  212. }
  213. public override ErrorInfo/*!*/ MakeStaticPropertyInstanceAccessError(PropertyTracker/*!*/ tracker, bool isAssignment, IList<DynamicMetaObject>/*!*/ parameters) {
  214. ContractUtils.RequiresNotNull(tracker, "tracker");
  215. ContractUtils.RequiresNotNull(parameters, "parameters");
  216. if (isAssignment) {
  217. return ErrorInfo.FromException(
  218. Ast.Call(
  219. typeof(PythonOps).GetMethod("StaticAssignmentFromInstanceError"),
  220. AstUtils.Constant(tracker),
  221. AstUtils.Constant(isAssignment)
  222. )
  223. );
  224. }
  225. return ErrorInfo.FromValue(
  226. Ast.Property(
  227. null,
  228. tracker.GetGetMethod(DomainManager.Configuration.PrivateBinding)
  229. )
  230. );
  231. }
  232. #region .NET member binding
  233. public override string GetTypeName(Type t) {
  234. return DynamicHelpers.GetPythonTypeFromType(t).Name;
  235. }
  236. public override MemberGroup/*!*/ GetMember(MemberRequestKind actionKind, Type type, string name) {
  237. MemberGroup mg;
  238. if (!_resolvedMembers.TryGetCachedMember(type, name, actionKind == MemberRequestKind.Get, out mg)) {
  239. mg = PythonTypeInfo.GetMemberAll(
  240. this,
  241. actionKind,
  242. type,
  243. name);
  244. _resolvedMembers.CacheSlot(type, actionKind == MemberRequestKind.Get, name, PythonTypeOps.GetSlot(mg, name, PrivateBinding), mg);
  245. }
  246. return mg ?? MemberGroup.EmptyGroup;
  247. }
  248. public override ErrorInfo/*!*/ MakeEventValidation(MemberGroup/*!*/ members, DynamicMetaObject eventObject, DynamicMetaObject/*!*/ value, OverloadResolverFactory/*!*/ factory) {
  249. EventTracker ev = (EventTracker)members[0];
  250. return ErrorInfo.FromValueNoError(
  251. Ast.Block(
  252. Ast.Call(
  253. typeof(PythonOps).GetMethod("SlotTrySetValue"),
  254. ((PythonOverloadResolverFactory)factory)._codeContext,
  255. AstUtils.Constant(PythonTypeOps.GetReflectedEvent(ev)),
  256. eventObject != null ? AstUtils.Convert(eventObject.Expression, typeof(object)) : AstUtils.Constant(null),
  257. AstUtils.Constant(null, typeof(PythonType)),
  258. AstUtils.Convert(value.Expression, typeof(object))
  259. ),
  260. Ast.Constant(null)
  261. )
  262. );
  263. }
  264. public override ErrorInfo MakeMissingMemberError(Type type, DynamicMetaObject self, string name) {
  265. string typeName;
  266. if (typeof(TypeTracker).IsAssignableFrom(type)) {
  267. typeName = "type";
  268. } else {
  269. typeName = NameConverter.GetTypeName(type);
  270. }
  271. return ErrorInfo.FromException(
  272. Ast.New(
  273. typeof(MissingMemberException).GetConstructor(new Type[] { typeof(string) }),
  274. AstUtils.Constant(String.Format("'{0}' object has no attribute '{1}'", typeName, name))
  275. )
  276. );
  277. }
  278. public override ErrorInfo MakeMissingMemberErrorForAssign(Type type, DynamicMetaObject self, string name) {
  279. if (self != null) {
  280. return MakeMissingMemberError(type, self, name);
  281. }
  282. return ErrorInfo.FromException(
  283. Ast.New(
  284. typeof(TypeErrorException).GetConstructor(new Type[] { typeof(string) }),
  285. AstUtils.Constant(String.Format("can't set attributes of built-in/extension type '{0}'", NameConverter.GetTypeName(type)))
  286. )
  287. );
  288. }
  289. public override ErrorInfo MakeMissingMemberErrorForAssignReadOnlyProperty(Type type, DynamicMetaObject self, string name) {
  290. return ErrorInfo.FromException(
  291. Ast.New(
  292. typeof(MissingMemberException).GetConstructor(new Type[] { typeof(string) }),
  293. AstUtils.Constant(String.Format("can't assign to read-only property {0} of type '{1}'", name, NameConverter.GetTypeName(type)))
  294. )
  295. );
  296. }
  297. public override ErrorInfo MakeMissingMemberErrorForDelete(Type type, DynamicMetaObject self, string name) {
  298. return MakeMissingMemberErrorForAssign(type, self, name);
  299. }
  300. /// <summary>
  301. /// Provides a way for the binder to provide a custom error message when lookup fails. Just
  302. /// doing this for the time being until we get a more robust error return mechanism.
  303. /// </summary>
  304. public override ErrorInfo MakeReadOnlyMemberError(Type type, string name) {
  305. return ErrorInfo.FromException(
  306. Ast.New(
  307. typeof(MissingMemberException).GetConstructor(new Type[] { typeof(string) }),
  308. AstUtils.Constant(
  309. String.Format("attribute '{0}' of '{1}' object is read-only",
  310. name,
  311. NameConverter.GetTypeName(type)
  312. )
  313. )
  314. )
  315. );
  316. }
  317. /// <summary>
  318. /// Provides a way for the binder to provide a custom error message when lookup fails. Just
  319. /// doing this for the time being until we get a more robust error return mechanism.
  320. /// </summary>
  321. public override ErrorInfo MakeUndeletableMemberError(Type type, string name) {
  322. return ErrorInfo.FromException(
  323. Ast.New(
  324. typeof(MissingMemberException).GetConstructor(new Type[] { typeof(string) }),
  325. AstUtils.Constant(
  326. String.Format("cannot delete attribute '{0}' of builtin type '{1}'",
  327. name,
  328. NameConverter.GetTypeName(type)
  329. )
  330. )
  331. )
  332. );
  333. }
  334. #endregion
  335. internal IList<Type> GetExtensionTypesInternal(Type t) {
  336. List<Type> res = new List<Type>(base.GetExtensionTypes(t));
  337. AddExtensionTypes(t, res);
  338. return res.ToArray();
  339. }
  340. public override bool IncludeExtensionMember(MemberInfo member) {
  341. return !member.DeclaringType.GetTypeInfo().IsDefined(typeof(PythonHiddenBaseClassAttribute), false);
  342. }
  343. public override IList<Type> GetExtensionTypes(Type t) {
  344. List<Type> list = new List<Type>();
  345. // Python includes the types themselves so we can use extension properties w/ CodeContext
  346. list.Add(t);
  347. list.AddRange(base.GetExtensionTypes(t));
  348. AddExtensionTypes(t, list);
  349. return list;
  350. }
  351. private void AddExtensionTypes(Type t, List<Type> list) {
  352. ExtensionTypeInfo extType;
  353. if (_sysTypes.TryGetValue(t, out extType)) {
  354. list.Add(extType.ExtensionType);
  355. }
  356. IList<Type> userExtensions;
  357. lock (_dlrExtensionTypes) {
  358. if (_dlrExtensionTypes.TryGetValue(t, out userExtensions)) {
  359. list.AddRange(userExtensions);
  360. }
  361. if (_registeredInterfaceExtensions) {
  362. foreach (Type ifaceType in t.GetInterfaces()) {
  363. IList<Type> extTypes;
  364. if (_dlrExtensionTypes.TryGetValue(ifaceType, out extTypes)) {
  365. list.AddRange(extTypes);
  366. }
  367. }
  368. }
  369. if (t.GetTypeInfo().IsGenericType) {
  370. // search for generic extensions, e.g. ListOfTOps<T> for List<T>,
  371. // we then make a new generic type out of the extension type.
  372. Type typeDef = t.GetGenericTypeDefinition();
  373. Type[] args = t.GetGenericArguments();
  374. if (_dlrExtensionTypes.TryGetValue(typeDef, out userExtensions)) {
  375. foreach (Type genExtType in userExtensions) {
  376. list.Add(genExtType.MakeGenericType(args));
  377. }
  378. }
  379. }
  380. }
  381. }
  382. public bool HasExtensionTypes(Type t) {
  383. return _dlrExtensionTypes.ContainsKey(t);
  384. }
  385. public override DynamicMetaObject ReturnMemberTracker(Type type, MemberTracker memberTracker) {
  386. var res = ReturnMemberTracker(type, memberTracker, PrivateBinding);
  387. return res ?? base.ReturnMemberTracker(type, memberTracker);
  388. }
  389. private static DynamicMetaObject ReturnMemberTracker(Type type, MemberTracker memberTracker, bool privateBinding) {
  390. switch (memberTracker.MemberType) {
  391. case TrackerTypes.TypeGroup:
  392. return new DynamicMetaObject(AstUtils.Constant(memberTracker), BindingRestrictions.Empty, memberTracker);
  393. case TrackerTypes.Type:
  394. return ReturnTypeTracker((TypeTracker)memberTracker);
  395. case TrackerTypes.Bound:
  396. return new DynamicMetaObject(ReturnBoundTracker((BoundMemberTracker)memberTracker, privateBinding), BindingRestrictions.Empty);
  397. case TrackerTypes.Property:
  398. return new DynamicMetaObject(ReturnPropertyTracker((PropertyTracker)memberTracker, privateBinding), BindingRestrictions.Empty);;
  399. case TrackerTypes.Event:
  400. return new DynamicMetaObject(Ast.Call(
  401. typeof(PythonOps).GetMethod("MakeBoundEvent"),
  402. AstUtils.Constant(PythonTypeOps.GetReflectedEvent((EventTracker)memberTracker)),
  403. AstUtils.Constant(null),
  404. AstUtils.Constant(type)
  405. ), BindingRestrictions.Empty);;
  406. case TrackerTypes.Field:
  407. return new DynamicMetaObject(ReturnFieldTracker((FieldTracker)memberTracker), BindingRestrictions.Empty);;
  408. case TrackerTypes.MethodGroup:
  409. return new DynamicMetaObject(ReturnMethodGroup((MethodGroup)memberTracker), BindingRestrictions.Empty); ;
  410. case TrackerTypes.Constructor:
  411. MethodBase[] ctors = CompilerHelpers.GetConstructors(type, privateBinding, true);
  412. object val;
  413. if (PythonTypeOps.IsDefaultNew(ctors)) {
  414. if (IsPythonType(type)) {
  415. val = InstanceOps.New;
  416. } else {
  417. val = InstanceOps.NewCls;
  418. }
  419. } else {
  420. val = PythonTypeOps.GetConstructor(type, InstanceOps.NonDefaultNewInst, ctors);
  421. }
  422. return new DynamicMetaObject(AstUtils.Constant(val), BindingRestrictions.Empty, val);
  423. case TrackerTypes.Custom:
  424. return new DynamicMetaObject(
  425. AstUtils.Constant(((PythonCustomTracker)memberTracker).GetSlot(), typeof(PythonTypeSlot)),
  426. BindingRestrictions.Empty,
  427. ((PythonCustomTracker)memberTracker).GetSlot()
  428. );
  429. }
  430. return null;
  431. }
  432. /// <summary>
  433. /// Gets the PythonBinder associated with tihs CodeContext
  434. /// </summary>
  435. public static PythonBinder/*!*/ GetBinder(CodeContext/*!*/ context) {
  436. return (PythonBinder)PythonContext.GetContext(context).Binder;
  437. }
  438. /// <summary>
  439. /// Performs .NET member resolution. This looks within the given type and also
  440. /// includes any extension members. Base classes and their extension members are
  441. /// not searched.
  442. /// </summary>
  443. public bool TryLookupSlot(CodeContext/*!*/ context, PythonType/*!*/ type, string name, out PythonTypeSlot slot) {
  444. Debug.Assert(type.IsSystemType);
  445. return TryLookupProtectedSlot(context, type, name, out slot);
  446. }
  447. /// <summary>
  448. /// Performs .NET member resolution. This looks within the given type and also
  449. /// includes any extension members. Base classes and their extension members are
  450. /// not searched.
  451. ///
  452. /// This version allows PythonType's for protected member resolution. It shouldn't
  453. /// be called externally for other purposes.
  454. /// </summary>
  455. internal bool TryLookupProtectedSlot(CodeContext/*!*/ context, PythonType/*!*/ type, string name, out PythonTypeSlot slot) {
  456. Type curType = type.UnderlyingSystemType;
  457. if (!_typeMembers.TryGetCachedSlot(curType, true, name, out slot)) {
  458. MemberGroup mg = PythonTypeInfo.GetMember(
  459. this,
  460. MemberRequestKind.Get,
  461. curType,
  462. name);
  463. slot = PythonTypeOps.GetSlot(mg, name, PrivateBinding);
  464. _typeMembers.CacheSlot(curType, true, name, slot, mg);
  465. }
  466. if (slot != null && (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context))) {
  467. return true;
  468. }
  469. slot = null;
  470. return false;
  471. }
  472. /// <summary>
  473. /// Performs .NET member resolution. This looks the type and any base types
  474. /// for members. It also searches for extension members in the type and any base types.
  475. /// </summary>
  476. public bool TryResolveSlot(CodeContext/*!*/ context, PythonType/*!*/ type, PythonType/*!*/ owner, string name, out PythonTypeSlot slot) {
  477. Type curType = type.UnderlyingSystemType;
  478. if (!_resolvedMembers.TryGetCachedSlot(curType, true, name, out slot)) {
  479. MemberGroup mg = PythonTypeInfo.GetMemberAll(
  480. this,
  481. MemberRequestKind.Get,
  482. curType,
  483. name);
  484. slot = PythonTypeOps.GetSlot(mg, name, PrivateBinding);
  485. _resolvedMembers.CacheSlot(curType, true, name, slot, mg);
  486. }
  487. if (slot != null && (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context))) {
  488. return true;
  489. }
  490. slot = null;
  491. return false;
  492. }
  493. /// <summary>
  494. /// Gets the member names which are defined in this type and any extension members.
  495. ///
  496. /// This search does not include members in any subtypes or their extension members.
  497. /// </summary>
  498. public void LookupMembers(CodeContext/*!*/ context, PythonType/*!*/ type, PythonDictionary/*!*/ memberNames) {
  499. if (!_typeMembers.IsFullyCached(type.UnderlyingSystemType, true)) {
  500. Dictionary<string, KeyValuePair<PythonTypeSlot, MemberGroup>> members = new Dictionary<string, KeyValuePair<PythonTypeSlot, MemberGroup>>();
  501. foreach (ResolvedMember rm in PythonTypeInfo.GetMembers(
  502. this,
  503. MemberRequestKind.Get,
  504. type.UnderlyingSystemType)) {
  505. if (!members.ContainsKey(rm.Name)) {
  506. members[rm.Name] = new KeyValuePair<PythonTypeSlot, MemberGroup>(
  507. PythonTypeOps.GetSlot(rm.Member, rm.Name, PrivateBinding),
  508. rm.Member
  509. );
  510. }
  511. }
  512. _typeMembers.CacheAll(type.UnderlyingSystemType, true, members);
  513. }
  514. foreach (KeyValuePair<string, PythonTypeSlot> kvp in _typeMembers.GetAllMembers(type.UnderlyingSystemType, true)) {
  515. PythonTypeSlot slot = kvp.Value;
  516. string name = kvp.Key;
  517. if (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context)) {
  518. memberNames[name] = slot;
  519. }
  520. }
  521. }
  522. /// <summary>
  523. /// Gets the member names which are defined in the type and any subtypes.
  524. ///
  525. /// This search includes members in the type and any subtypes as well as extension
  526. /// types of the type and its subtypes.
  527. /// </summary>
  528. public void ResolveMemberNames(CodeContext/*!*/ context, PythonType/*!*/ type, PythonType/*!*/ owner, Dictionary<string, string>/*!*/ memberNames) {
  529. if (!_resolvedMembers.IsFullyCached(type.UnderlyingSystemType, true)) {
  530. Dictionary<string, KeyValuePair<PythonTypeSlot, MemberGroup>> members = new Dictionary<string, KeyValuePair<PythonTypeSlot, MemberGroup>>();
  531. foreach (ResolvedMember rm in PythonTypeInfo.GetMembersAll(
  532. this,
  533. MemberRequestKind.Get,
  534. type.UnderlyingSystemType)) {
  535. if (!members.ContainsKey(rm.Name)) {
  536. members[rm.Name] = new KeyValuePair<PythonTypeSlot, MemberGroup>(
  537. PythonTypeOps.GetSlot(rm.Member, rm.Name, PrivateBinding),
  538. rm.Member
  539. );
  540. }
  541. }
  542. _resolvedMembers.CacheAll(type.UnderlyingSystemType, true, members);
  543. }
  544. foreach (KeyValuePair<string, PythonTypeSlot> kvp in _resolvedMembers.GetAllMembers(type.UnderlyingSystemType, true)) {
  545. PythonTypeSlot slot = kvp.Value;
  546. string name = kvp.Key;
  547. if (slot.IsAlwaysVisible || PythonOps.IsClsVisible(context)) {
  548. memberNames[name] = name;
  549. }
  550. }
  551. }
  552. private static Expression ReturnFieldTracker(FieldTracker fieldTracker) {
  553. return AstUtils.Constant(PythonTypeOps.GetReflectedField(fieldTracker.Field));
  554. }
  555. private static Expression ReturnMethodGroup(MethodGroup methodGroup) {
  556. return AstUtils.Constant(PythonTypeOps.GetFinalSlotForFunction(GetBuiltinFunction(methodGroup)));
  557. }
  558. private static Expression ReturnBoundTracker(BoundMemberTracker boundMemberTracker, bool privateBinding) {
  559. MemberTracker boundTo = boundMemberTracker.BoundTo;
  560. switch (boundTo.MemberType) {
  561. case TrackerTypes.Property:
  562. PropertyTracker pt = (PropertyTracker)boundTo;
  563. Debug.Assert(pt.GetIndexParameters().Length > 0);
  564. return Ast.New(
  565. typeof(ReflectedIndexer).GetConstructor(new Type[] { typeof(ReflectedIndexer), typeof(object) }),
  566. AstUtils.Constant(new ReflectedIndexer(((ReflectedPropertyTracker)pt).Property, NameType.Property, privateBinding)),
  567. boundMemberTracker.Instance.Expression
  568. );
  569. case TrackerTypes.Event:
  570. return Ast.Call(
  571. typeof(PythonOps).GetMethod("MakeBoundEvent"),
  572. AstUtils.Constant(PythonTypeOps.GetReflectedEvent((EventTracker)boundMemberTracker.BoundTo)),
  573. boundMemberTracker.Instance.Expression,
  574. AstUtils.Constant(boundMemberTracker.DeclaringType)
  575. );
  576. case TrackerTypes.MethodGroup:
  577. return Ast.Call(
  578. typeof(PythonOps).GetMethod("MakeBoundBuiltinFunction"),
  579. AstUtils.Constant(GetBuiltinFunction((MethodGroup)boundTo)),
  580. AstUtils.Convert(
  581. boundMemberTracker.Instance.Expression,
  582. typeof(object)
  583. )
  584. );
  585. }
  586. throw new NotImplementedException();
  587. }
  588. private static BuiltinFunction GetBuiltinFunction(MethodGroup mg) {
  589. MethodBase[] methods = new MethodBase[mg.Methods.Count];
  590. for (int i = 0; i < mg.Methods.Count; i++) {
  591. methods[i] = mg.Methods[i].Method;
  592. }
  593. return PythonTypeOps.GetBuiltinFunction(
  594. mg.DeclaringType,
  595. mg.Methods[0].Name,
  596. (PythonTypeOps.GetMethodFunctionType(mg.DeclaringType, methods) & (~FunctionType.FunctionMethodMask)) |
  597. (mg.ContainsInstance ? FunctionType.Method : FunctionType.None) |
  598. (mg.ContainsStatic ? FunctionType.Function : FunctionType.None),
  599. mg.GetMethodBases()
  600. );
  601. }
  602. private static Expression ReturnPropertyTracker(PropertyTracker propertyTracker, bool privateBinding) {
  603. return AstUtils.Constant(PythonTypeOps.GetReflectedProperty(propertyTracker, new MemberGroup(propertyTracker), privateBinding));
  604. }
  605. private static DynamicMetaObject ReturnTypeTracker(TypeTracker memberTracker) {
  606. // all non-group types get exposed as PythonType's
  607. object value = DynamicHelpers.GetPythonTypeFromType(memberTracker.Type);
  608. return new DynamicMetaObject(Ast.Constant(value), BindingRestrictions.Empty, value);
  609. }
  610. internal ScriptDomainManager/*!*/ DomainManager {
  611. get {
  612. return _context.DomainManager;
  613. }
  614. }
  615. private class ExtensionTypeInfo {
  616. public Type ExtensionType;
  617. public string PythonName;
  618. public ExtensionTypeInfo(Type extensionType, string pythonName) {
  619. ExtensionType = extensionType;
  620. PythonName = pythonName;
  621. }
  622. }
  623. internal static void AssertNotExtensionType(Type t) {
  624. foreach (ExtensionTypeInfo typeinfo in _sysTypes.Values) {
  625. Debug.Assert(typeinfo.ExtensionType != t);
  626. }
  627. Debug.Assert(t != typeof(InstanceOps));
  628. }
  629. /// <summary>
  630. /// Creates the initial table of extension types. These are standard extension that we apply
  631. /// to well known .NET types to make working with them better. Being added to this table does
  632. /// not make a type a Python type though so that it's members are generally accessible w/o an
  633. /// import clr and their type is not re-named.
  634. /// </summary>
  635. private static Dictionary<Type/*!*/, IList<Type/*!*/>/*!*/>/*!*/ MakeExtensionTypes() {
  636. Dictionary<Type, IList<Type>> res = new Dictionary<Type, IList<Type>>();
  637. #if FEATURE_DBNULL
  638. res[typeof(DBNull)] = new Type[] { typeof(DBNullOps) };
  639. #endif
  640. res[typeof(List<>)] = new Type[] { typeof(ListOfTOps<>) };
  641. res[typeof(Dictionary<,>)] = new Type[] { typeof(DictionaryOfTOps<,>) };
  642. res[typeof(Array)] = new Type[] { typeof(ArrayOps) };
  643. res[typeof(Assembly)] = new Type[] { typeof(PythonAssemblyOps) };
  644. res[typeof(Enum)] = new Type[] { typeof(EnumOps) };
  645. res[typeof(Delegate)] = new Type[] { typeof(DelegateOps) };
  646. res[typeof(Byte)] = new Type[] { typeof(ByteOps) };
  647. res[typeof(SByte)] = new Type[] { typeof(SByteOps) };
  648. res[typeof(Int16)] = new Type[] { typeof(Int16Ops) };
  649. res[typeof(UInt16)] = new Type[] { typeof(UInt16Ops) };
  650. res[typeof(UInt32)] = new Type[] { typeof(UInt32Ops) };
  651. res[typeof(Int64)] = new Type[] { typeof(Int64Ops) };
  652. res[typeof(UInt64)] = new Type[] { typeof(UInt64Ops) };
  653. res[typeof(char)] = new Type[] { typeof(CharOps) };
  654. res[typeof(decimal)] = new Type[] { typeof(DecimalOps) };
  655. res[typeof(float)] = new Type[] { typeof(SingleOps) };
  656. return res;
  657. }
  658. /// <summary>
  659. /// Creates a table of standard .NET types which are also standard Python types. These types have a standard
  660. /// set of extension types which are shared between all runtimes.
  661. /// </summary>
  662. private static Dictionary<Type/*!*/, ExtensionTypeInfo/*!*/>/*!*/ MakeSystemTypes() {
  663. Dictionary<Type/*!*/, ExtensionTypeInfo/*!*/> res = new Dictionary<Type, ExtensionTypeInfo>();
  664. // Native CLR types
  665. res[typeof(object)] = new ExtensionTypeInfo(typeof(ObjectOps), "object");
  666. res[typeof(string)] = new ExtensionTypeInfo(typeof(StringOps), "str");
  667. res[typeof(int)] = new ExtensionTypeInfo(typeof(Int32Ops), "int");
  668. res[typeof(bool)] = new ExtensionTypeInfo(typeof(BoolOps), "bool");
  669. res[typeof(double)] = new ExtensionTypeInfo(typeof(DoubleOps), "float");
  670. res[typeof(ValueType)] = new ExtensionTypeInfo(typeof(ValueType), "ValueType"); // just hiding it's methods in the inheritance hierarchy
  671. // MS.Math types
  672. res[typeof(BigInteger)] = new ExtensionTypeInfo(typeof(BigIntegerOps), "long");
  673. res[typeof(Complex)] = new ExtensionTypeInfo(typeof(ComplexOps), "complex");
  674. // DLR types
  675. res[typeof(DynamicNull)] = new ExtensionTypeInfo(typeof(NoneTypeOps), "NoneType");
  676. res[typeof(IDictionary<object, object>)] = new ExtensionTypeInfo(typeof(DictionaryOps), "dict");
  677. res[typeof(NamespaceTracker)] = new ExtensionTypeInfo(typeof(NamespaceTrackerOps), "namespace#");
  678. res[typeof(TypeGroup)] = new ExtensionTypeInfo(typeof(TypeGroupOps), "type-collision");
  679. res[typeof(TypeTracker)] = new ExtensionTypeInfo(typeof(TypeTrackerOps), "type-collision");
  680. return res;
  681. }
  682. internal static string GetTypeNameInternal(Type t) {
  683. ExtensionTypeInfo extInfo;
  684. if (_sysTypes.TryGetValue(t, out extInfo)) {
  685. return extInfo.PythonName;
  686. }
  687. var attr = t.GetTypeInfo().GetCustomAttributes<PythonTypeAttribute>(false).FirstOrDefault();
  688. if (attr != null && attr.Name != null) {
  689. return attr.Name;
  690. }
  691. return t.Name;
  692. }
  693. public static bool IsExtendedType(Type/*!*/ t) {
  694. Debug.Assert(t != null);
  695. return _sysTypes.ContainsKey(t);
  696. }
  697. public static bool IsPythonType(Type/*!*/ t) {
  698. Debug.Assert(t != null);
  699. return _sysTypes.ContainsKey(t) || t.GetTypeInfo().IsDefined(typeof(PythonTypeAttribute), false);
  700. }
  701. /// <summary>
  702. /// Event handler for when our domain manager has an assembly loaded by the user hosting the script
  703. /// runtime. Here we can gather any information regarding extension methods.
  704. ///
  705. /// Currently DLR-style extension methods become immediately available w/o an explicit import step.
  706. /// </summary>
  707. private void DomainManager_AssemblyLoaded(object sender, AssemblyLoadedEventArgs e) {
  708. Assembly asm = e.Assembly;
  709. var attrs = asm.GetCustomAttributes<ExtensionTypeAttribute>();
  710. if (attrs.Any()) {
  711. lock (_dlrExtensionTypes) {
  712. foreach (ExtensionTypeAttribute attr in attrs) {
  713. if (attr.Extends.IsInterface()) {
  714. _registeredInterfaceExtensions = true;
  715. }
  716. IList<Type> typeList;
  717. if (!_dlrExtensionTypes.TryGetValue(attr.Extends, out typeList)) {
  718. _dlrExtensionTypes[attr.Extends] = typeList = new List<Type>();
  719. } else if (typeList.IsReadOnly) {
  720. _dlrExtensionTypes[attr.Extends] = typeList = new List<Type>(typeList);
  721. }
  722. // don't add extension types twice even if we receive multiple assembly loads
  723. if (!typeList.Contains(attr.ExtensionType)) {
  724. typeList.Add(attr.ExtensionType);
  725. }
  726. }
  727. }
  728. }
  729. TopNamespaceTracker.PublishComTypes(asm);
  730. // Add it to the references tuple if we
  731. // loaded a new assembly.
  732. ClrModule.ReferencesList rl = _context.ReferencedAssemblies;
  733. lock (rl) {
  734. rl.Add(asm);
  735. }
  736. #if FEATURE_REFEMIT
  737. // load any compiled code that has been cached...
  738. LoadScriptCode(_context, asm);
  739. #endif
  740. // load any Python modules
  741. _context.LoadBuiltins(_context.BuiltinModules, asm, true);
  742. // load any cached new types
  743. NewTypeMaker.LoadNewTypes(asm);
  744. }
  745. #if FEATURE_REFEMIT
  746. private static void LoadScriptCode(PythonContext/*!*/ pc, Assembly/*!*/ asm) {
  747. ScriptCode[] codes = SavableScriptCode.LoadFromAssembly(pc.DomainManager, asm);
  748. foreach (ScriptCode sc in codes) {
  749. pc.GetCompiledLoader().AddScriptCode(sc);
  750. }
  751. }
  752. #endif
  753. internal PythonContext/*!*/ Context {
  754. get {
  755. return _context;
  756. }
  757. }
  758. /// <summary>
  759. /// Provides a cache from Type/name -> PythonTypeSlot and also allows access to
  760. /// all members (and remembering whether all members are cached).
  761. /// </summary>
  762. private class SlotCache {
  763. private Dictionary<CachedInfoKey/*!*/, SlotCacheInfo/*!*/> _cachedInfos;
  764. /// <summary>
  765. /// Writes to a cache the result of a type lookup. Null values are allowed for the slots and they indicate that
  766. /// the value does not exist.
  767. /// </summary>
  768. public void CacheSlot(Type/*!*/ type, bool isGetMember, string/*!*/ name, PythonTypeSlot slot, MemberGroup/*!*/ memberGroup) {
  769. Debug.Assert(type != null); Debug.Assert(name != null);
  770. EnsureInfo();
  771. lock (_cachedInfos) {
  772. SlotCacheInfo slots = GetSlotForType(type, isGetMember);
  773. if (slots.ResolvedAll && slot == null && memberGroup.Count == 0) {
  774. // nothing to cache, and we know we don't need to cache non-hits.
  775. return;
  776. }
  777. slots.Members[name] = new KeyValuePair<PythonTypeSlot, MemberGroup>(slot, memberGroup);
  778. }
  779. }
  780. /// <summary>
  781. /// Looks up a cached type slot for the specified member and type. This may return true and return a null slot - that indicates
  782. /// that a cached result for a member which doesn't exist has been stored. Otherwise it returns true if a slot is found or
  783. /// false if it is not.
  784. /// </summary>
  785. public bool TryGetCachedSlot(Type/*!*/ type, bool isGetMember, string/*!*/ name, out PythonTypeSlot slot) {
  786. Debug.Assert(type != null); Debug.Assert(name != null);
  787. if (_cachedInfos != null) {
  788. lock (_cachedInfos) {
  789. SlotCacheInfo slots;
  790. if (_cachedInfos.TryGetValue(new CachedInfoKey(type, isGetMember), out slots) &&
  791. (slots.TryGetSlot(name, out slot) || slots.ResolvedAll)) {
  792. return true;
  793. }
  794. }
  795. }
  796. slot = null;
  797. return false;
  798. }
  799. /// <summary>
  800. /// Looks up a cached member group for the specified member and type. This may return true and return a null group - that indicates
  801. /// that a cached result for a member which doesn't exist has been stored. Otherwise it returns true if a group is found or
  802. /// false if it is not.
  803. /// </summary>
  804. public bool TryGetCachedMember(Type/*!*/ type, string/*!*/ name, bool getMemberAction, out MemberGroup/*!*/ group) {
  805. Debug.Assert(type != null); Debug.Assert(name != null);
  806. if (_cachedInfos != null) {
  807. lock (_cachedInfos) {
  808. SlotCacheInfo slots;
  809. if (_cachedInfos.TryGetValue(new CachedInfoKey(type, getMemberAction), out slots) &&
  810. (slots.TryGetMember(name, out group) || (getMemberAction && slots.ResolvedAll))) {
  811. return true;
  812. }
  813. }
  814. }
  815. group = MemberGroup.EmptyGroup;
  816. return false;
  817. }
  818. /// <summary>
  819. /// Checks to see if all members have been populated for the provided type.
  820. /// </summary>
  821. public bool IsFullyCached(Type/*!*/ type, bool isGetMember) {
  822. if (_cachedInfos != null) {
  823. lock (_cachedInfos) {
  824. SlotCacheInfo info;
  825. if (_cachedInfos.TryGetValue(new CachedInfoKey(type, isGetMember), out info)) {
  826. return info.ResolvedAll;
  827. }
  828. }
  829. }
  830. return false;
  831. }
  832. /// <summary>
  833. /// Populates the type with all the provided members and marks the type
  834. /// as being fully cached.
  835. ///
  836. /// The dictionary is used for the internal storage and should not be modified after
  837. /// providing it to the cache.
  838. /// </summary>
  839. public void CacheAll(Type/*!*/ type, bool isGetMember, Dictionary<string/*!*/, KeyValuePair<PythonTypeSlot/*!*/, MemberGroup/*!*/>> members) {
  840. Debug.Assert(type != null);
  841. EnsureInfo();
  842. lock (_cachedInfos) {
  843. SlotCacheInfo slots = GetSlotForType(type, isGetMember);
  844. slots.Members = members;
  845. slots.ResolvedAll = true;
  846. }
  847. }
  848. /// <summary>
  849. /// Returns an enumerable object which provides access to all the members of the provided type.
  850. ///
  851. /// The caller must check that the type is fully cached and populate the cache if it isn't before
  852. /// calling this method.
  853. /// </summary>
  854. public IEnumerable<KeyValuePair<string/*!*/, PythonTypeSlot/*!*/>>/*!*/ GetAllMembers(Type/*!*/ type, bool isGetMember) {
  855. Debug.Assert(type != null);
  856. SlotCacheInfo info = GetSlotForType(type, isGetMember);
  857. Debug.Assert(info.ResolvedAll);
  858. foreach (KeyValuePair<string, PythonTypeSlot> slot in info.GetAllSlots()) {
  859. if (slot.Value != null) {
  860. yield return slot;
  861. }
  862. }
  863. }
  864. private SlotCacheInfo/*!*/ GetSlotForType(Type/*!*/ type, bool isGetMember) {
  865. SlotCacheInfo slots;
  866. var key = new CachedInfoKey(type, isGetMember);
  867. if (!_cachedInfos.TryGetValue(key, out slots)) {
  868. _cachedInfos[key] = slots = new SlotCacheInfo();
  869. }
  870. return slots;
  871. }
  872. class CachedInfoKey : IEquatable<CachedInfoKey> {
  873. public readonly Type Type;
  874. public readonly bool IsGetMember;
  875. public CachedInfoKey(Type type, bool isGetMember) {
  876. Type = type;
  877. IsGetMember = isGetMember;
  878. }
  879. #region IEquatable<CachedInfoKey> Members
  880. public bool Equals(CachedInfoKey other) {
  881. return other.Type == Type && other.IsGetMember == IsGetMember;
  882. }
  883. #endregion
  884. public override bool Equals(object obj) {
  885. CachedInfoKey other = obj as CachedInfoKey;
  886. if (other != null) {
  887. return Equals(other);
  888. }
  889. return false;
  890. }
  891. public override int GetHashCode() {
  892. return Type.GetHashCode() ^ (IsGetMember ? -1 : 0);
  893. }
  894. }
  895. private void EnsureInfo() {
  896. if (_cachedInfos == null) {
  897. Interlocked.CompareExchange(ref _cachedInfos, new Dictionary<CachedInfoKey/*!*/, SlotCacheInfo>(), null);
  898. }
  899. }
  900. private class SlotCacheInfo {
  901. public SlotCacheInfo() {
  902. Members = new Dictionary<string/*!*/, KeyValuePair<PythonTypeSlot, MemberGroup/*!*/>>(StringComparer.Ordinal);
  903. }
  904. public bool TryGetSlot(string/*!*/ name, out PythonTypeSlot slot) {
  905. Debug.Assert(name != null);
  906. KeyValuePair<PythonTypeSlot, MemberGroup> kvp;
  907. if (Members.TryGetValue(name, out kvp)) {
  908. slot = kvp.Key;
  909. return true;
  910. }
  911. slot = null;
  912. return false;
  913. }
  914. public bool TryGetMember(string/*!*/ name, out MemberGroup/*!*/ group) {
  915. Debug.Assert(name != null);
  916. KeyValuePair<PythonTypeSlot, MemberGroup> kvp;
  917. if (Members.TryGetValue(name, out kvp)) {
  918. group = kvp.Value;
  919. return true;
  920. }
  921. group = MemberGroup.EmptyGroup;
  922. return false;
  923. }
  924. public IEnumerable<KeyValuePair<string/*!*/, PythonTypeSlot>>/*!*/ GetAllSlots() {
  925. foreach (KeyValuePair<string, KeyValuePair<PythonTypeSlot, MemberGroup>> kvp in Members) {
  926. yield return new KeyValuePair<string, PythonTypeSlot>(kvp.Key, kvp.Value.Key);
  927. }
  928. }
  929. public Dictionary<string/*!*/, KeyValuePair<PythonTypeSlot, MemberGroup/*!*/>>/*!*/ Members;
  930. public bool ResolvedAll;
  931. }
  932. }
  933. }
  934. }