PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

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