PageRenderTime 67ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

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