PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/Types/OldInstance.cs

http://github.com/IronLanguages/main
C# | 1062 lines | 811 code | 219 blank | 32 comment | 163 complexity | fa688a50d1a381d654dd7c05a59eb023 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  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. #endif
  22. using System;
  23. using System.Collections;
  24. using System.Collections.Generic;
  25. using System.ComponentModel;
  26. using System.Diagnostics;
  27. using System.Dynamic;
  28. using System.Runtime.CompilerServices;
  29. using System.Runtime.Serialization;
  30. using Microsoft.Scripting;
  31. using Microsoft.Scripting.Runtime;
  32. using Microsoft.Scripting.Utils;
  33. using IronPython.Runtime.Operations;
  34. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  35. namespace IronPython.Runtime.Types {
  36. [PythonType("instance")]
  37. [Serializable]
  38. [DebuggerTypeProxy(typeof(OldInstance.OldInstanceDebugView)), DebuggerDisplay("old-style instance of {ClassName}")]
  39. public sealed partial class OldInstance :
  40. ICodeFormattable,
  41. #if CLR2
  42. IValueEquality,
  43. #endif
  44. #if FEATURE_CUSTOM_TYPE_DESCRIPTOR
  45. ICustomTypeDescriptor,
  46. #endif
  47. ISerializable,
  48. IWeakReferenceable,
  49. IDynamicMetaObjectProvider,
  50. IPythonMembersList,
  51. Binding.IFastGettable
  52. {
  53. private PythonDictionary _dict;
  54. internal OldClass _class;
  55. private WeakRefTracker _weakRef; // initialized if user defines finalizer on class or instance
  56. private static PythonDictionary MakeDictionary(OldClass oldClass) {
  57. return new PythonDictionary(new CustomInstanceDictionaryStorage(oldClass.OptimizedInstanceNames, oldClass.OptimizedInstanceNamesVersion));
  58. }
  59. public OldInstance(CodeContext/*!*/ context, OldClass @class) {
  60. _class = @class;
  61. _dict = MakeDictionary(@class);
  62. if (_class.HasFinalizer) {
  63. // class defines finalizer, we get it automatically.
  64. AddFinalizer(context);
  65. }
  66. }
  67. public OldInstance(CodeContext/*!*/ context, OldClass @class, PythonDictionary dict) {
  68. _class = @class;
  69. _dict = dict ?? PythonDictionary.MakeSymbolDictionary();
  70. if (_class.HasFinalizer) {
  71. // class defines finalizer, we get it automatically.
  72. AddFinalizer(context);
  73. }
  74. }
  75. #if FEATURE_SERIALIZATION
  76. private OldInstance(SerializationInfo info, StreamingContext context) {
  77. _class = (OldClass)info.GetValue("__class__", typeof(OldClass));
  78. _dict = MakeDictionary(_class);
  79. List<object> keys = (List<object>)info.GetValue("keys", typeof(List<object>));
  80. List<object> values = (List<object>)info.GetValue("values", typeof(List<object>));
  81. for (int i = 0; i < keys.Count; i++) {
  82. _dict[keys[i]] = values[i];
  83. }
  84. }
  85. #pragma warning disable 169 // unused method - called via reflection from serialization
  86. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")]
  87. private void GetObjectData(SerializationInfo info, StreamingContext context) {
  88. ContractUtils.RequiresNotNull(info, "info");
  89. info.AddValue("__class__", _class);
  90. List<object> keys = new List<object>();
  91. List<object> values = new List<object>();
  92. foreach (object o in _dict.keys()) {
  93. keys.Add(o);
  94. object value;
  95. bool res = _dict.TryGetValue(o, out value);
  96. Debug.Assert(res);
  97. values.Add(value);
  98. }
  99. info.AddValue("keys", keys);
  100. info.AddValue("values", values);
  101. }
  102. #pragma warning restore 169
  103. #endif
  104. /// <summary>
  105. /// Returns the dictionary used to store state for this object
  106. /// </summary>
  107. internal PythonDictionary Dictionary {
  108. get { return _dict; }
  109. }
  110. internal string ClassName {
  111. get {
  112. return _class.Name;
  113. }
  114. }
  115. public static bool operator true(OldInstance self) {
  116. return (bool)self.__nonzero__(DefaultContext.Default);
  117. }
  118. public static bool operator false(OldInstance self) {
  119. return !(bool)self.__nonzero__(DefaultContext.Default);
  120. }
  121. #region Object overrides
  122. public override string ToString() {
  123. object ret = InvokeOne(this, "__str__");
  124. if (ret != NotImplementedType.Value) {
  125. string strRet;
  126. if (Converter.TryConvertToString(ret, out strRet) && strRet != null) {
  127. return strRet;
  128. }
  129. throw PythonOps.TypeError("__str__ returned non-string type ({0})", PythonTypeOps.GetName(ret));
  130. }
  131. return __repr__(DefaultContext.Default);
  132. }
  133. #endregion
  134. #region ICodeFormattable Members
  135. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  136. object ret = InvokeOne(this, "__repr__");
  137. if(ret != NotImplementedType.Value) {
  138. string strRet;
  139. if (Converter.TryConvertToString(ret, out strRet) && strRet != null) {
  140. return strRet;
  141. }
  142. throw PythonOps.TypeError("__repr__ returned non-string type ({0})", PythonTypeOps.GetName(ret));
  143. }
  144. return string.Format("<{0} instance at {1}>", _class.FullName, PythonOps.HexId(this));
  145. }
  146. #endregion
  147. [return: MaybeNotImplemented]
  148. public object __divmod__(CodeContext context, object divmod) {
  149. object value;
  150. if (TryGetBoundCustomMember(context, "__divmod__", out value)) {
  151. return PythonCalls.Call(context, value, divmod);
  152. }
  153. return NotImplementedType.Value;
  154. }
  155. [return: MaybeNotImplemented]
  156. public static object __rdivmod__(CodeContext context, object divmod, [NotNull]OldInstance self) {
  157. object value;
  158. if (self.TryGetBoundCustomMember(context, "__rdivmod__", out value)) {
  159. return PythonCalls.Call(context, value, divmod);
  160. }
  161. return NotImplementedType.Value;
  162. }
  163. public object __coerce__(CodeContext context, object other) {
  164. object value;
  165. if (TryGetBoundCustomMember(context, "__coerce__", out value)) {
  166. return PythonCalls.Call(context, value, other);
  167. }
  168. return NotImplementedType.Value;
  169. }
  170. public object __len__(CodeContext context) {
  171. object value;
  172. if (TryGetBoundCustomMember(context, "__len__", out value)) {
  173. return PythonOps.CallWithContext(context, value);
  174. }
  175. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__len__");
  176. }
  177. public object __pos__(CodeContext context) {
  178. object value;
  179. if (TryGetBoundCustomMember(context, "__pos__", out value)) {
  180. return PythonOps.CallWithContext(context, value);
  181. }
  182. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__pos__");
  183. }
  184. [SpecialName]
  185. public object GetItem(CodeContext context, object item) {
  186. return PythonOps.Invoke(context, this, "__getitem__", item);
  187. }
  188. [SpecialName]
  189. public void SetItem(CodeContext context, object item, object value) {
  190. PythonOps.Invoke(context, this, "__setitem__", item, value);
  191. }
  192. [SpecialName]
  193. public object DeleteItem(CodeContext context, object item) {
  194. object value;
  195. if (TryGetBoundCustomMember(context, "__delitem__", out value)) {
  196. return PythonCalls.Call(context, value, item);
  197. }
  198. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__delitem__");
  199. }
  200. [Python3Warning("in 3.x, __getslice__ has been removed; use __getitem__")]
  201. public object __getslice__(CodeContext context, int i, int j) {
  202. object callable;
  203. if (TryRawGetAttr(context, "__getslice__", out callable)) {
  204. return PythonCalls.Call(context, callable, i, j);
  205. } else if (TryRawGetAttr(context, "__getitem__", out callable)) {
  206. return PythonCalls.Call(context, callable, new Slice(i, j));
  207. }
  208. throw PythonOps.TypeError("instance {0} does not have __getslice__ or __getitem__", _class.Name);
  209. }
  210. [Python3Warning("in 3.x, __setslice__ has been removed; use __setitem__")]
  211. public void __setslice__(CodeContext context, int i, int j, object value) {
  212. object callable;
  213. if (TryRawGetAttr(context, "__setslice__", out callable)) {
  214. PythonCalls.Call(context, callable, i, j, value);
  215. return;
  216. } else if (TryRawGetAttr(context, "__setitem__", out callable)) {
  217. PythonCalls.Call(context, callable, new Slice(i, j), value);
  218. return;
  219. }
  220. throw PythonOps.TypeError("instance {0} does not have __setslice__ or __setitem__", _class.Name);
  221. }
  222. [Python3Warning("in 3.x, __delslice__ has been removed; use __delitem__")]
  223. public object __delslice__(CodeContext context, int i, int j) {
  224. object callable;
  225. if (TryRawGetAttr(context, "__delslice__", out callable)) {
  226. return PythonCalls.Call(context, callable, i, j);
  227. } else if (TryRawGetAttr(context, "__delitem__", out callable)) {
  228. return PythonCalls.Call(context, callable, new Slice(i, j));
  229. }
  230. throw PythonOps.TypeError("instance {0} does not have __delslice__ or __delitem__", _class.Name);
  231. }
  232. public object __index__(CodeContext context) {
  233. object value;
  234. if (TryGetBoundCustomMember(context, "__int__", out value)) {
  235. return PythonOps.CallWithContext(context, value);
  236. }
  237. throw PythonOps.TypeError("object cannot be converted to an index");
  238. }
  239. public object __neg__(CodeContext context) {
  240. object value;
  241. if (TryGetBoundCustomMember(context, "__neg__", out value)) {
  242. return PythonOps.CallWithContext(context, value);
  243. }
  244. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__neg__");
  245. }
  246. public object __abs__(CodeContext context) {
  247. object value;
  248. if (TryGetBoundCustomMember(context, "__abs__", out value)) {
  249. return PythonOps.CallWithContext(context, value);
  250. }
  251. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__abs__");
  252. }
  253. public object __invert__(CodeContext context) {
  254. object value;
  255. if (TryGetBoundCustomMember(context, "__invert__", out value)) {
  256. return PythonOps.CallWithContext(context, value);
  257. }
  258. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__invert__");
  259. }
  260. public object __contains__(CodeContext context, object index) {
  261. object value;
  262. if (TryGetBoundCustomMember(context, "__contains__", out value)) {
  263. return PythonCalls.Call(context, value, index);
  264. }
  265. IEnumerator ie = PythonOps.GetEnumerator(this);
  266. while (ie.MoveNext()) {
  267. if (PythonOps.EqualRetBool(context, ie.Current, index)) return ScriptingRuntimeHelpers.True;
  268. }
  269. return ScriptingRuntimeHelpers.False;
  270. }
  271. [SpecialName]
  272. public object Call(CodeContext context) {
  273. return Call(context, ArrayUtils.EmptyObjects);
  274. }
  275. [SpecialName]
  276. public object Call(CodeContext context, object args) {
  277. try {
  278. PythonOps.FunctionPushFrame(PythonContext.GetContext(context));
  279. object value;
  280. if (TryGetBoundCustomMember(context, "__call__", out value)) {
  281. return PythonOps.CallWithContext(context, value, args);
  282. }
  283. } finally {
  284. PythonOps.FunctionPopFrame();
  285. }
  286. throw PythonOps.AttributeError("{0} instance has no __call__ method", _class.Name);
  287. }
  288. [SpecialName]
  289. public object Call(CodeContext context, params object[] args) {
  290. try {
  291. PythonOps.FunctionPushFrame(PythonContext.GetContext(context));
  292. object value;
  293. if (TryGetBoundCustomMember(context, "__call__", out value)) {
  294. return PythonOps.CallWithContext(context, value, args);
  295. }
  296. } finally {
  297. PythonOps.FunctionPopFrame();
  298. }
  299. throw PythonOps.AttributeError("{0} instance has no __call__ method", _class.Name);
  300. }
  301. [SpecialName]
  302. public object Call(CodeContext context, [ParamDictionary]IDictionary<object, object> dict, params object[] args) {
  303. try {
  304. PythonOps.FunctionPushFrame(PythonContext.GetContext(context));
  305. object value;
  306. if (TryGetBoundCustomMember(context, "__call__", out value)) {
  307. return context.LanguageContext.CallWithKeywords(value, args, dict);
  308. }
  309. } finally {
  310. PythonOps.FunctionPopFrame();
  311. }
  312. throw PythonOps.AttributeError("{0} instance has no __call__ method", _class.Name);
  313. }
  314. public object __nonzero__(CodeContext context) {
  315. object value;
  316. if (TryGetBoundCustomMember(context, "__nonzero__", out value)) {
  317. return PythonOps.CallWithContext(context, value);
  318. }
  319. if (TryGetBoundCustomMember(context, "__len__", out value)) {
  320. value = PythonOps.CallWithContext(context, value);
  321. // Convert resulting object to the desired type
  322. if (value is Int32 || value is BigInteger) {
  323. return ScriptingRuntimeHelpers.BooleanToObject(Converter.ConvertToBoolean(value));
  324. }
  325. throw PythonOps.TypeError("an integer is required, got {0}", PythonTypeOps.GetName(value));
  326. }
  327. return ScriptingRuntimeHelpers.True;
  328. }
  329. public object __hex__(CodeContext context) {
  330. object value;
  331. if (TryGetBoundCustomMember(context, "__hex__", out value)) {
  332. return PythonOps.CallWithContext(context, value);
  333. }
  334. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__hex__");
  335. }
  336. public object __oct__(CodeContext context) {
  337. object value;
  338. if (TryGetBoundCustomMember(context, "__oct__", out value)) {
  339. return PythonOps.CallWithContext(context, value);
  340. }
  341. throw PythonOps.AttributeErrorForOldInstanceMissingAttribute(_class.Name, "__oct__");
  342. }
  343. public object __int__(CodeContext context) {
  344. object value;
  345. if (PythonOps.TryGetBoundAttr(context, this, "__int__", out value)) {
  346. return PythonOps.CallWithContext(context, value);
  347. }
  348. return NotImplementedType.Value;
  349. }
  350. public object __long__(CodeContext context) {
  351. object value;
  352. if (PythonOps.TryGetBoundAttr(context, this, "__long__", out value)) {
  353. return PythonOps.CallWithContext(context, value);
  354. }
  355. return NotImplementedType.Value;
  356. }
  357. public object __float__(CodeContext context) {
  358. object value;
  359. if (PythonOps.TryGetBoundAttr(context, this, "__float__", out value)) {
  360. return PythonOps.CallWithContext(context, value);
  361. }
  362. return NotImplementedType.Value;
  363. }
  364. public object __complex__(CodeContext context) {
  365. object value;
  366. if (TryGetBoundCustomMember(context, "__complex__", out value)) {
  367. return PythonOps.CallWithContext(context, value);
  368. }
  369. return NotImplementedType.Value;
  370. }
  371. public object __getattribute__(CodeContext context, string name) {
  372. object res;
  373. if (TryGetBoundCustomMember(context, name, out res)) {
  374. return res;
  375. }
  376. throw PythonOps.AttributeError("{0} instance has no attribute '{1}'", _class._name, name);
  377. }
  378. internal object GetBoundMember(CodeContext context, string name) {
  379. object ret;
  380. if (TryGetBoundCustomMember(context, name, out ret)) {
  381. return ret;
  382. }
  383. throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'",
  384. PythonTypeOps.GetName(this), name);
  385. }
  386. #region ICustomMembers Members
  387. internal bool TryGetBoundCustomMember(CodeContext context, string name, out object value) {
  388. if (name == "__dict__") {
  389. //!!! user code can modify __del__ property of __dict__ behind our back
  390. value = _dict;
  391. return true;
  392. } else if (name == "__class__") {
  393. value = _class;
  394. return true;
  395. }
  396. if (TryRawGetAttr(context, name, out value)) return true;
  397. if (name != "__getattr__") {
  398. object getattr;
  399. if (TryRawGetAttr(context, "__getattr__", out getattr)) {
  400. try {
  401. value = PythonCalls.Call(context, getattr, name);
  402. return true;
  403. } catch (MissingMemberException) {
  404. // __getattr__ raised AttributeError, return false.
  405. }
  406. }
  407. }
  408. return false;
  409. }
  410. internal void SetCustomMember(CodeContext context, string name, object value) {
  411. object setFunc;
  412. if (name == "__class__") {
  413. SetClass(value);
  414. } else if (name == "__dict__") {
  415. SetDict(context, value);
  416. } else if (_class.HasSetAttr && _class.TryLookupSlot("__setattr__", out setFunc)) {
  417. PythonCalls.Call(context, _class.GetOldStyleDescriptor(context, setFunc, this, _class), name.ToString(), value);
  418. } else if (name == "__del__") {
  419. SetFinalizer(context, name, value);
  420. } else {
  421. _dict[name] = value;
  422. }
  423. }
  424. private void SetFinalizer(CodeContext/*!*/ context, string name, object value) {
  425. if (!HasFinalizer()) {
  426. // user is defining __del__ late bound for the 1st time
  427. AddFinalizer(context);
  428. }
  429. _dict[name] = value;
  430. }
  431. private void SetDict(CodeContext/*!*/ context, object value) {
  432. PythonDictionary dict = value as PythonDictionary;
  433. if (dict == null) {
  434. throw PythonOps.TypeError("__dict__ must be set to a dictionary");
  435. }
  436. if (HasFinalizer() && !_class.HasFinalizer) {
  437. if (!dict.ContainsKey("__del__")) {
  438. ClearFinalizer();
  439. }
  440. } else if (dict.ContainsKey("__del__")) {
  441. AddFinalizer(context);
  442. }
  443. _dict = dict;
  444. }
  445. private void SetClass(object value) {
  446. OldClass oc = value as OldClass;
  447. if (oc == null) {
  448. throw PythonOps.TypeError("__class__ must be set to class");
  449. }
  450. _class = oc;
  451. }
  452. internal bool DeleteCustomMember(CodeContext context, string name) {
  453. if (name == "__class__") throw PythonOps.TypeError("__class__ must be set to class");
  454. if (name == "__dict__") throw PythonOps.TypeError("__dict__ must be set to a dictionary");
  455. object delFunc;
  456. if (_class.HasDelAttr && _class.TryLookupSlot("__delattr__", out delFunc)) {
  457. PythonCalls.Call(context, _class.GetOldStyleDescriptor(context, delFunc, this, _class), name.ToString());
  458. return true;
  459. }
  460. if (name == "__del__") {
  461. // removing finalizer
  462. if (HasFinalizer() && !_class.HasFinalizer) {
  463. ClearFinalizer();
  464. }
  465. }
  466. if (!_dict.Remove(name)) {
  467. throw PythonOps.AttributeError("{0} is not a valid attribute", name);
  468. }
  469. return true;
  470. }
  471. #endregion
  472. #region IMembersList Members
  473. IList<string> IMembersList.GetMemberNames() {
  474. return PythonOps.GetStringMemberList(this);
  475. }
  476. IList<object> IPythonMembersList.GetMemberNames(CodeContext/*!*/ context) {
  477. PythonDictionary attrs = new PythonDictionary(_dict);
  478. OldClass.RecurseAttrHierarchy(this._class, attrs);
  479. return PythonOps.MakeListFromSequence(attrs);
  480. }
  481. #endregion
  482. [return: MaybeNotImplemented]
  483. public object __cmp__(CodeContext context, object other) {
  484. OldInstance oiOther = other as OldInstance;
  485. // CPython raises this if called directly, but not via cmp(os,ns) which still calls the user __cmp__
  486. //if(!(oiOther is OldInstance))
  487. // throw Ops.TypeError("instance.cmp(x,y) -> y must be an instance, got {0}", Ops.StringRepr(DynamicHelpers.GetPythonType(other)));
  488. object res = InternalCompare("__cmp__", other);
  489. if (res != NotImplementedType.Value) return res;
  490. if (oiOther != null) {
  491. res = oiOther.InternalCompare("__cmp__", this);
  492. if (res != NotImplementedType.Value) return ((int)res) * -1;
  493. }
  494. return NotImplementedType.Value;
  495. }
  496. private object CompareForwardReverse(object other, string forward, string reverse) {
  497. object res = InternalCompare(forward, other);
  498. if (res != NotImplementedType.Value) return res;
  499. OldInstance oi = other as OldInstance;
  500. if (oi != null) {
  501. // comparison operators are reflexive
  502. return oi.InternalCompare(reverse, this);
  503. }
  504. return NotImplementedType.Value;
  505. }
  506. [return: MaybeNotImplemented]
  507. public static object operator >([NotNull]OldInstance self, object other) {
  508. return self.CompareForwardReverse(other, "__gt__", "__lt__");
  509. }
  510. [return: MaybeNotImplemented]
  511. public static object operator <([NotNull]OldInstance self, object other) {
  512. return self.CompareForwardReverse(other, "__lt__", "__gt__");
  513. }
  514. [return: MaybeNotImplemented]
  515. public static object operator >=([NotNull]OldInstance self, object other) {
  516. return self.CompareForwardReverse(other, "__ge__", "__le__");
  517. }
  518. [return: MaybeNotImplemented]
  519. public static object operator <=([NotNull]OldInstance self, object other) {
  520. return self.CompareForwardReverse(other, "__le__", "__ge__");
  521. }
  522. private object InternalCompare(string cmp, object other) {
  523. return InvokeOne(this, other, cmp);
  524. }
  525. #region ICustomTypeDescriptor Members
  526. #if FEATURE_CUSTOM_TYPE_DESCRIPTOR
  527. AttributeCollection ICustomTypeDescriptor.GetAttributes() {
  528. return CustomTypeDescHelpers.GetAttributes(this);
  529. }
  530. string ICustomTypeDescriptor.GetClassName() {
  531. return CustomTypeDescHelpers.GetClassName(this);
  532. }
  533. string ICustomTypeDescriptor.GetComponentName() {
  534. return CustomTypeDescHelpers.GetComponentName(this);
  535. }
  536. TypeConverter ICustomTypeDescriptor.GetConverter() {
  537. return CustomTypeDescHelpers.GetConverter(this);
  538. }
  539. EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
  540. return CustomTypeDescHelpers.GetDefaultEvent(this);
  541. }
  542. PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
  543. return CustomTypeDescHelpers.GetDefaultProperty(this);
  544. }
  545. object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
  546. return CustomTypeDescHelpers.GetEditor(this, editorBaseType);
  547. }
  548. EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
  549. return CustomTypeDescHelpers.GetEvents(this, attributes);
  550. }
  551. EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
  552. return CustomTypeDescHelpers.GetEvents(this);
  553. }
  554. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
  555. return CustomTypeDescHelpers.GetProperties(this, attributes);
  556. }
  557. PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
  558. return CustomTypeDescHelpers.GetProperties(this);
  559. }
  560. object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
  561. return CustomTypeDescHelpers.GetPropertyOwner(this, pd);
  562. }
  563. #endif
  564. #endregion
  565. #region IWeakReferenceable Members
  566. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  567. return _weakRef;
  568. }
  569. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  570. _weakRef = value;
  571. return true;
  572. }
  573. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  574. ((IWeakReferenceable)this).SetWeakRef(value);
  575. }
  576. #endregion
  577. #region Rich Equality
  578. // Specific rich equality support for when the user calls directly from oldinstance type.
  579. public int __hash__(CodeContext/*!*/ context) {
  580. object func;
  581. object ret = InvokeOne(this, "__hash__");
  582. if (ret != NotImplementedType.Value) {
  583. if (ret is BigInteger) {
  584. return BigIntegerOps.__hash__((BigInteger)ret);
  585. } else if (!(ret is int))
  586. throw PythonOps.TypeError("expected int from __hash__, got {0}", PythonTypeOps.GetName(ret));
  587. return (int)ret;
  588. }
  589. if (TryGetBoundCustomMember(context, "__cmp__", out func) ||
  590. TryGetBoundCustomMember(context, "__eq__", out func)) {
  591. throw PythonOps.TypeError("unhashable instance");
  592. }
  593. return base.GetHashCode();
  594. }
  595. public override int GetHashCode() {
  596. object ret;
  597. try {
  598. ret = InvokeOne(this, "__hash__");
  599. } catch {
  600. return base.GetHashCode();
  601. }
  602. if (ret != NotImplementedType.Value) {
  603. if (ret is int) {
  604. return (int)ret;
  605. }
  606. if (ret is BigInteger) {
  607. return BigIntegerOps.__hash__((BigInteger)ret);
  608. }
  609. }
  610. return base.GetHashCode();
  611. }
  612. [return: MaybeNotImplemented]
  613. public object __eq__(object other) {
  614. object res = InvokeBoth(other, "__eq__");
  615. if (res != NotImplementedType.Value) {
  616. return res;
  617. }
  618. return NotImplementedType.Value;
  619. }
  620. private object InvokeBoth(object other, string si) {
  621. object res = InvokeOne(this, other, si);
  622. if (res != NotImplementedType.Value) {
  623. return res;
  624. }
  625. OldInstance oi = other as OldInstance;
  626. if (oi != null) {
  627. res = InvokeOne(oi, this, si);
  628. if (res != NotImplementedType.Value) {
  629. return res;
  630. }
  631. }
  632. return NotImplementedType.Value;
  633. }
  634. private static object InvokeOne(OldInstance self, object other, string si) {
  635. object func;
  636. try {
  637. if (!self.TryGetBoundCustomMember(DefaultContext.Default, si, out func)) {
  638. return NotImplementedType.Value;
  639. }
  640. } catch (MissingMemberException) {
  641. return NotImplementedType.Value;
  642. }
  643. return PythonOps.CallWithContext(DefaultContext.Default, func, other);
  644. }
  645. private static object InvokeOne(OldInstance self, object other, object other2, string si) {
  646. object func;
  647. try {
  648. if (!self.TryGetBoundCustomMember(DefaultContext.Default, si, out func)) {
  649. return NotImplementedType.Value;
  650. }
  651. } catch (MissingMemberException) {
  652. return NotImplementedType.Value;
  653. }
  654. return PythonOps.CallWithContext(DefaultContext.Default, func, other, other2);
  655. }
  656. private static object InvokeOne(OldInstance self, string si) {
  657. object func;
  658. try {
  659. if (!self.TryGetBoundCustomMember(DefaultContext.Default, si, out func)) {
  660. return NotImplementedType.Value;
  661. }
  662. } catch (MissingMemberException) {
  663. return NotImplementedType.Value;
  664. }
  665. return PythonOps.CallWithContext(DefaultContext.Default, func);
  666. }
  667. [return: MaybeNotImplemented]
  668. public object __ne__(object other) {
  669. object res = InvokeBoth(other, "__ne__");
  670. if (res != NotImplementedType.Value) {
  671. return res;
  672. }
  673. return NotImplementedType.Value;
  674. }
  675. [return: MaybeNotImplemented]
  676. [SpecialName]
  677. public static object Power([NotNull]OldInstance self, object other, object mod) {
  678. object res = InvokeOne(self, other, mod, "__pow__");
  679. if (res != NotImplementedType.Value) return res;
  680. return NotImplementedType.Value;
  681. }
  682. #endregion
  683. #region ISerializable Members
  684. #if FEATURE_SERIALIZATION
  685. void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
  686. info.AddValue("__class__", _class);
  687. info.AddValue("__dict__", _dict);
  688. }
  689. #endif
  690. #endregion
  691. #region Private Implementation Details
  692. private void RecurseAttrHierarchyInt(OldClass oc, IDictionary<string, object> attrs) {
  693. foreach (KeyValuePair<object, object> kvp in oc._dict._storage.GetItems()) {
  694. string strKey = kvp.Key as string;
  695. if (strKey != null) {
  696. if (!attrs.ContainsKey(strKey)) {
  697. attrs.Add(strKey, strKey);
  698. }
  699. }
  700. }
  701. // recursively get attrs in parent hierarchy
  702. if (oc.BaseClasses.Count != 0) {
  703. foreach (OldClass parent in oc.BaseClasses) {
  704. RecurseAttrHierarchyInt(parent, attrs);
  705. }
  706. }
  707. }
  708. private void AddFinalizer(CodeContext/*!*/ context) {
  709. InstanceFinalizer oif = new InstanceFinalizer(context, this);
  710. _weakRef = new WeakRefTracker(this, oif, oif);
  711. }
  712. private void ClearFinalizer() {
  713. if (_weakRef == null) return;
  714. WeakRefTracker wrt = _weakRef;
  715. if (wrt != null) {
  716. // find our handler and remove it (other users could have created weak refs to us)
  717. for (int i = 0; i < wrt.HandlerCount; i++) {
  718. if (wrt.GetHandlerCallback(i) is InstanceFinalizer) {
  719. wrt.RemoveHandlerAt(i);
  720. break;
  721. }
  722. }
  723. // we removed the last handler
  724. if (wrt.HandlerCount == 0) {
  725. GC.SuppressFinalize(wrt);
  726. _weakRef = null;
  727. }
  728. }
  729. }
  730. private bool HasFinalizer() {
  731. if (_weakRef != null) {
  732. WeakRefTracker wrt = _weakRef;
  733. if (wrt != null) {
  734. for (int i = 0; i < wrt.HandlerCount; i++) {
  735. if (wrt.GetHandlerCallback(i) is InstanceFinalizer) {
  736. return true;
  737. }
  738. }
  739. }
  740. }
  741. return false;
  742. }
  743. private bool TryRawGetAttr(CodeContext context, string name, out object ret) {
  744. if (_dict._storage.TryGetValue(name, out ret)) {
  745. return true;
  746. }
  747. if (_class.TryLookupSlot(name, out ret)) {
  748. ret = _class.GetOldStyleDescriptor(context, ret, this, _class);
  749. return true;
  750. }
  751. return false;
  752. }
  753. #endregion
  754. #region IValueEquality Members
  755. #if CLR2
  756. int IValueEquality.GetValueHashCode() {
  757. return GetHashCode();
  758. }
  759. bool IValueEquality.ValueEquals(object other) {
  760. return Equals(other);
  761. }
  762. #endif
  763. #endregion
  764. #region IDynamicMetaObjectProvider Members
  765. DynamicMetaObject/*!*/ IDynamicMetaObjectProvider.GetMetaObject(Expression/*!*/ parameter) {
  766. return new Binding.MetaOldInstance(parameter, BindingRestrictions.Empty, this);
  767. }
  768. #endregion
  769. internal class OldInstanceDebugView {
  770. private readonly OldInstance _userObject;
  771. public OldInstanceDebugView(OldInstance userObject) {
  772. _userObject = userObject;
  773. }
  774. public OldClass __class__ {
  775. get {
  776. return _userObject._class;
  777. }
  778. }
  779. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  780. internal List<ObjectDebugView> Members {
  781. get {
  782. var res = new List<ObjectDebugView>();
  783. if (_userObject._dict != null) {
  784. foreach (var v in _userObject._dict) {
  785. res.Add(new ObjectDebugView(v.Key, v.Value));
  786. }
  787. }
  788. return res;
  789. }
  790. }
  791. }
  792. class FastOldInstanceGet {
  793. private readonly string _name;
  794. public FastOldInstanceGet(string name) {
  795. _name = name;
  796. }
  797. public object Target(CallSite site, object instance, CodeContext context) {
  798. OldInstance oi = instance as OldInstance;
  799. if (oi != null) {
  800. object res;
  801. if (oi.TryGetBoundCustomMember(context, _name, out res)) {
  802. return res;
  803. }
  804. throw PythonOps.AttributeError("{0} instance has no attribute '{1}'", oi._class.Name, _name);
  805. }
  806. return ((CallSite<Func<CallSite, object, CodeContext, object>>)site).Update(site, instance, context);
  807. }
  808. public object LightThrowTarget(CallSite site, object instance, CodeContext context) {
  809. OldInstance oi = instance as OldInstance;
  810. if (oi != null) {
  811. object res;
  812. if (oi.TryGetBoundCustomMember(context, _name, out res)) {
  813. return res;
  814. }
  815. return LightExceptions.Throw(PythonOps.AttributeError("{0} instance has no attribute '{1}'", oi._class.Name, _name));
  816. }
  817. return ((CallSite<Func<CallSite, object, CodeContext, object>>)site).Update(site, instance, context);
  818. }
  819. public object NoThrowTarget(CallSite site, object instance, CodeContext context) {
  820. OldInstance oi = instance as OldInstance;
  821. if (oi != null) {
  822. object res;
  823. if (oi.TryGetBoundCustomMember(context, _name, out res)) {
  824. return res;
  825. }
  826. return OperationFailed.Value;
  827. }
  828. return ((CallSite<Func<CallSite, object, CodeContext, object>>)site).Update(site, instance, context);
  829. }
  830. }
  831. #region IFastGettable Members
  832. T Binding.IFastGettable.MakeGetBinding<T>(System.Runtime.CompilerServices.CallSite<T> site, Binding.PythonGetMemberBinder binder, CodeContext state, string name) {
  833. if (binder.IsNoThrow) {
  834. return (T)(object)new Func<CallSite, object, CodeContext, object>(new FastOldInstanceGet(name).NoThrowTarget);
  835. } else if (binder.SupportsLightThrow) {
  836. return (T)(object)new Func<CallSite, object, CodeContext, object>(new FastOldInstanceGet(name).LightThrowTarget);
  837. } else {
  838. return (T)(object)new Func<CallSite, object, CodeContext, object>(new FastOldInstanceGet(name).Target);
  839. }
  840. }
  841. #endregion
  842. }
  843. }