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

/Languages/IronPython/IronPython/Runtime/Operations/InstanceOps.cs

http://github.com/IronLanguages/main
C# | 967 lines | 669 code | 187 blank | 111 comment | 149 complexity | bed853c4dbea7f4bd247486b1066f060 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. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Diagnostics;
  24. using System.Dynamic;
  25. using System.Reflection;
  26. using System.Runtime.CompilerServices;
  27. using Microsoft.Scripting;
  28. using Microsoft.Scripting.Runtime;
  29. using Microsoft.Scripting.Utils;
  30. using IronPython.Runtime.Exceptions;
  31. using IronPython.Runtime.Types;
  32. namespace IronPython.Runtime.Operations {
  33. /// <summary>
  34. /// InstanceOps contains methods that get added to CLS types depending on what
  35. /// methods and constructors they define. These have not been added directly to
  36. /// PythonType since they need to be added conditionally.
  37. ///
  38. /// Possibilities include:
  39. ///
  40. /// __new__, one of 3 __new__ sets can be added:
  41. /// DefaultNew - This is the __new__ used for a PythonType (list, dict, object, etc...) that
  42. /// has only 1 default public constructor that takes no parameters. These types are
  43. /// mutable types, and __new__ returns a new instance of the type, and __init__ can be used
  44. /// to re-initialize the types. This __new__ allows an unlimited number of arguments to
  45. /// be passed if a non-default __init__ is also defined.
  46. ///
  47. /// NonDefaultNew - This is used when a type has more than one constructor, or only has one
  48. /// that takes more than zero parameters. This __new__ does not allow an arbitrary # of
  49. /// extra arguments.
  50. ///
  51. /// DefaultNewCls - This is the default new used for CLS types that have only a single ctor
  52. /// w/ an arbitray number of arguments. This constructor allows setting of properties
  53. /// based upon an extra set of kw-args, e.g.: System.Windows.Forms.Button(Text='abc'). It
  54. /// is only used on non-Python types.
  55. ///
  56. /// __init__:
  57. /// For types that do not define __init__ we have an __init__ function that takes an
  58. /// unlimited number of arguments and does nothing. All types share the same reference
  59. /// to 1 instance of this.
  60. ///
  61. /// next: Defined when a type is an enumerator to expose the Python iter protocol.
  62. ///
  63. ///
  64. /// repr: Added for types that override ToString
  65. ///
  66. /// get: added for types that implement IDescriptor
  67. /// </summary>
  68. public static class InstanceOps {
  69. #region Construction
  70. [MultiRuntimeAware]
  71. private static BuiltinFunction _New;
  72. internal static readonly BuiltinFunction NewCls = CreateFunction("__new__", "DefaultNew", "DefaultNewClsKW");
  73. internal static readonly BuiltinFunction OverloadedNew = CreateFunction("__new__", "OverloadedNewBasic", "OverloadedNewKW", "OverloadedNewClsKW");
  74. internal static readonly BuiltinFunction NonDefaultNewInst = CreateNonDefaultNew();
  75. [MultiRuntimeAware]
  76. internal static BuiltinMethodDescriptor _Init;
  77. internal static BuiltinMethodDescriptor Init {
  78. get {
  79. if (_Init == null) {
  80. _Init = GetInitMethod();
  81. }
  82. return _Init;
  83. }
  84. }
  85. internal static BuiltinFunction New {
  86. get {
  87. if (_New == null) {
  88. _New = (BuiltinFunction)PythonTypeOps.GetSlot(
  89. PythonTypeInfo.GetExtensionMemberGroup(typeof(object), typeof(ObjectOps).GetMember("__new__")),
  90. "__new__",
  91. false // privateBinding
  92. );
  93. }
  94. return _New;
  95. }
  96. }
  97. internal static BuiltinFunction CreateNonDefaultNew() {
  98. return CreateFunction("__new__", "NonDefaultNew", "NonDefaultNewKW", "NonDefaultNewKWNoParams");
  99. }
  100. public static object DefaultNew(CodeContext context, PythonType type\u00F8, params object[] args\u00F8) {
  101. if (type\u00F8 == null) {
  102. throw PythonOps.TypeError(
  103. "__new__ expected type object, got {0}",
  104. PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8))
  105. );
  106. }
  107. CheckNewArgs(context, null, args\u00F8, type\u00F8);
  108. return type\u00F8.CreateInstance(context);
  109. }
  110. public static object DefaultNewClsKW(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary<object, object> kwargs\u00F8, params object[] args\u00F8) {
  111. object res = DefaultNew(context, type\u00F8, args\u00F8);
  112. if (kwargs\u00F8.Count > 0) {
  113. foreach (KeyValuePair<object, object> kvp in (IDictionary<object, object>)kwargs\u00F8) {
  114. PythonOps.SetAttr(context,
  115. res,
  116. kvp.Key.ToString(),
  117. kvp.Value);
  118. }
  119. }
  120. return res;
  121. }
  122. public static object OverloadedNewBasic(CodeContext context, SiteLocalStorage<CallSite<Func<CallSite, CodeContext, object, object[], object>>> storage, BuiltinFunction overloads\u00F8, PythonType type\u00F8, params object[] args\u00F8) {
  123. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  124. if (args\u00F8 == null) args\u00F8 = new object[1];
  125. return overloads\u00F8.Call(context, storage, null, args\u00F8);
  126. }
  127. public static object OverloadedNewKW(CodeContext context, BuiltinFunction overloads\u00F8, PythonType type\u00F8, [ParamDictionary]IDictionary<object, object> kwargs\u00F8) {
  128. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  129. return overloads\u00F8.Call(context, null, null, ArrayUtils.EmptyObjects, kwargs\u00F8);
  130. }
  131. public static object OverloadedNewClsKW(CodeContext context, BuiltinFunction overloads\u00F8, PythonType type\u00F8, [ParamDictionary]IDictionary<object, object> kwargs\u00F8, params object[] args\u00F8) {
  132. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  133. if (args\u00F8 == null) args\u00F8 = new object[1];
  134. return overloads\u00F8.Call(context, null, null, args\u00F8, kwargs\u00F8);
  135. }
  136. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "args\u00F8")]
  137. public static void DefaultInit(CodeContext context, object self, params object[] args\u00F8) {
  138. }
  139. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "self"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kwargs\u00F8"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "args\u00F8")]
  140. public static void DefaultInitKW(CodeContext context, object self, [ParamDictionary]IDictionary<object, object> kwargs\u00F8, params object[] args\u00F8) {
  141. }
  142. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")]
  143. [StaticExtensionMethod]
  144. public static object NonDefaultNew(CodeContext context, PythonType type\u00F8, params object[] args\u00F8) {
  145. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  146. if (args\u00F8 == null) args\u00F8 = new object[1];
  147. return type\u00F8.CreateInstance(context, args\u00F8);
  148. }
  149. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")]
  150. [StaticExtensionMethod]
  151. public static object NonDefaultNewKW(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary<object, object> kwargs\u00F8, params object[] args\u00F8) {
  152. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  153. if (args\u00F8 == null) args\u00F8 = new object[1];
  154. string []names;
  155. GetKeywordArgs(kwargs\u00F8, args\u00F8, out args\u00F8, out names);
  156. return type\u00F8.CreateInstance(context, args\u00F8, names);
  157. }
  158. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "context")]
  159. [StaticExtensionMethod]
  160. public static object NonDefaultNewKWNoParams(CodeContext context, PythonType type\u00F8, [ParamDictionary]IDictionary<object, object> kwargs\u00F8) {
  161. if (type\u00F8 == null) throw PythonOps.TypeError("__new__ expected type object, got {0}", PythonOps.Repr(context, DynamicHelpers.GetPythonType(type\u00F8)));
  162. string[] names;
  163. object[] args;
  164. GetKeywordArgs(kwargs\u00F8, ArrayUtils.EmptyObjects, out args, out names);
  165. return type\u00F8.CreateInstance(context, args, names);
  166. }
  167. #endregion
  168. #region Iteration
  169. // 3.0-only
  170. public static object IterMethodForString(string self) {
  171. return PythonOps.StringEnumerator(self);
  172. }
  173. // 3.0-only
  174. public static object IterMethodForBytes(Bytes self) {
  175. return PythonOps.BytesIntEnumerator(self);
  176. }
  177. public static object IterMethodForEnumerator(IEnumerator self) {
  178. return self;
  179. }
  180. public static object IterMethodForEnumerable(IEnumerable self) {
  181. return self.GetEnumerator();
  182. }
  183. public static object IterMethodForGenericEnumerator<T>(IEnumerator<T> self) {
  184. return self;
  185. }
  186. public static object IterMethodForGenericEnumerable<T>(IEnumerable<T> self) {
  187. return self.GetEnumerator();
  188. }
  189. public static object NextMethod(object self) {
  190. IEnumerator i = (IEnumerator)self;
  191. lock (i) {
  192. if (i.MoveNext()) return i.Current;
  193. }
  194. throw PythonOps.StopIteration();
  195. }
  196. #endregion
  197. /// <summary>
  198. /// __dir__(self) -> Returns the list of members defined on a foreign IDynamicMetaObjectProvider.
  199. /// </summary>
  200. public static List DynamicDir(CodeContext/*!*/ context, IDynamicMetaObjectProvider self) {
  201. List res = new List(self.GetMetaObject(Expression.Parameter(typeof(object))).GetDynamicMemberNames());
  202. // add in the non-dynamic members from the dynamic objects base class.
  203. Type t = self.GetType();
  204. while (typeof(IDynamicMetaObjectProvider).IsAssignableFrom(t)) {
  205. t = t.GetTypeInfo().BaseType;
  206. }
  207. res.extend(DynamicHelpers.GetPythonTypeFromType(t).GetMemberNames(context));
  208. res.sort(context);
  209. return res;
  210. }
  211. public static int LengthMethod(ICollection self) {
  212. return self.Count;
  213. }
  214. public static int GenericLengthMethod<T>(ICollection<T> self) {
  215. return self.Count;
  216. }
  217. #region Representation and Formatting
  218. public static string SimpleRepr(object self) {
  219. return String.Format("<{0} object at {1}>",
  220. PythonTypeOps.GetName(self),
  221. PythonOps.HexId(self));
  222. }
  223. public static string FancyRepr(object self) {
  224. PythonType pt = (PythonType)DynamicHelpers.GetPythonType(self);
  225. // we can't call ToString on a UserType because we'll stack overflow, so
  226. // only do FancyRepr for reflected types.
  227. if (pt.IsSystemType) {
  228. string toStr = self.ToString();
  229. if (toStr == null) toStr = String.Empty;
  230. // get the type name to display (CLI name or Python name)
  231. Type type = pt.UnderlyingSystemType;
  232. string typeName = type.FullName;
  233. // Get the underlying .ToString() representation. Truncate multiple
  234. // lines, and don't display it if it's object's default representation (type name)
  235. // skip initial empty lines:
  236. int i = 0;
  237. while (i < toStr.Length && (toStr[i] == '\r' || toStr[i] == '\n')) i++;
  238. // read the first non-empty line:
  239. int j = i;
  240. while (j < toStr.Length && toStr[j] != '\r' && toStr[j] != '\n') j++;
  241. // skip following empty lines:
  242. int k = j;
  243. while (k < toStr.Length && (toStr[k] == '\r' || toStr[k] == '\n')) k++;
  244. if (j > i) {
  245. string first_non_empty_line = toStr.Substring(i, j - i);
  246. bool has_multiple_non_empty_lines = k < toStr.Length;
  247. return String.Format("<{0} object at {1} [{2}{3}]>",
  248. typeName,
  249. PythonOps.HexId(self),
  250. first_non_empty_line,
  251. has_multiple_non_empty_lines ? "..." : String.Empty);
  252. } else {
  253. return String.Format("<{0} object at {1}>",
  254. typeName,
  255. PythonOps.HexId(self));
  256. }
  257. }
  258. return SimpleRepr(self);
  259. }
  260. public static object ReprHelper(CodeContext context, object self) {
  261. return ((ICodeFormattable)self).__repr__(context);
  262. }
  263. public static string ToStringMethod(object self) {
  264. string res = self.ToString();
  265. if (res == null) return String.Empty;
  266. return res;
  267. }
  268. public static string Format(IFormattable formattable, string format) {
  269. return formattable.ToString(format, null);
  270. }
  271. #endregion
  272. #region Comparison and Hashing
  273. #if CLR2
  274. // Value equality helpers: These are the default implementation for classes that implement
  275. // IValueEquality. We promote the ReflectedType to having these helper methods which will
  276. // automatically test the type and return NotImplemented for mixed comparisons. For non-mixed
  277. // comparisons we have a fully optimized version which returns bool.
  278. public static bool ValueEqualsMethod<T>(T x, [NotNull]T y)
  279. where T : IValueEquality {
  280. return x.ValueEquals(y);
  281. }
  282. public static bool ValueNotEqualsMethod<T>(T x, [NotNull]T y)
  283. where T : IValueEquality {
  284. return !x.ValueEquals(y);
  285. }
  286. [return: MaybeNotImplemented]
  287. public static object ValueEqualsMethod<T>([NotNull]T x, object y)
  288. where T : IValueEquality {
  289. if (!(y is T)) return NotImplementedType.Value;
  290. return ScriptingRuntimeHelpers.BooleanToObject(x.ValueEquals(y));
  291. }
  292. [return: MaybeNotImplemented]
  293. public static object ValueNotEqualsMethod<T>([NotNull]T x, object y)
  294. where T : IValueEquality {
  295. if (!(y is T)) return NotImplementedType.Value;
  296. return ScriptingRuntimeHelpers.BooleanToObject(!x.ValueEquals(y));
  297. }
  298. [return: MaybeNotImplemented]
  299. public static object ValueEqualsMethod<T>(object y, [NotNull]T x)
  300. where T : IValueEquality {
  301. if (!(y is T)) return NotImplementedType.Value;
  302. return ScriptingRuntimeHelpers.BooleanToObject(x.ValueEquals(y));
  303. }
  304. [return: MaybeNotImplemented]
  305. public static object ValueNotEqualsMethod<T>(object y, [NotNull]T x)
  306. where T : IValueEquality {
  307. if (!(y is T)) return NotImplementedType.Value;
  308. return ScriptingRuntimeHelpers.BooleanToObject(!x.ValueEquals(y));
  309. }
  310. #endif
  311. public static bool EqualsMethod(object x, object y) {
  312. return x.Equals(y);
  313. }
  314. public static bool NotEqualsMethod(object x, object y) {
  315. return !x.Equals(y);
  316. }
  317. #if CLR2
  318. public static bool TypeNotEqualsMethod(Type x, object y) {
  319. ContractUtils.RequiresNotNull(x, "x");
  320. PythonType pythonType = y as PythonType;
  321. if (pythonType != null) {
  322. return !x.Equals((Type)pythonType);
  323. }
  324. Type type = y as Type;
  325. return y == null || !x.Equals(type);
  326. }
  327. #endif
  328. // Structural Equality and Hashing Helpers
  329. public static int StructuralHashMethod(CodeContext/*!*/ context, IStructuralEquatable x) {
  330. return x.GetHashCode(PythonContext.GetContext(context).EqualityComparerNonGeneric);
  331. }
  332. public static bool StructuralEqualityMethod<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  333. where T : IStructuralEquatable {
  334. return x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric);
  335. }
  336. public static bool StructuralInequalityMethod<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  337. where T : IStructuralEquatable {
  338. return !x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric);
  339. }
  340. [return: MaybeNotImplemented]
  341. public static object StructuralEqualityMethod<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  342. where T : IStructuralEquatable {
  343. if (!(y is T)) return NotImplementedType.Value;
  344. return ScriptingRuntimeHelpers.BooleanToObject(
  345. x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  346. );
  347. }
  348. [return: MaybeNotImplemented]
  349. public static object StructuralInequalityMethod<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  350. where T : IStructuralEquatable {
  351. if (!(y is T)) return NotImplementedType.Value;
  352. return ScriptingRuntimeHelpers.BooleanToObject(
  353. !x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  354. );
  355. }
  356. [return: MaybeNotImplemented]
  357. public static object StructuralEqualityMethod<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  358. where T : IStructuralEquatable {
  359. if (!(y is T)) return NotImplementedType.Value;
  360. return ScriptingRuntimeHelpers.BooleanToObject(
  361. x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  362. );
  363. }
  364. [return: MaybeNotImplemented]
  365. public static object StructuralInequalityMethod<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  366. where T : IStructuralEquatable {
  367. if (!(y is T)) return NotImplementedType.Value;
  368. return ScriptingRuntimeHelpers.BooleanToObject(
  369. !x.Equals(y, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  370. );
  371. }
  372. // Structural Comparison Helpers
  373. private static int StructuralCompare(CodeContext/*!*/ context, IStructuralComparable x, object y) {
  374. return x.CompareTo(y, PythonContext.GetContext(context).GetComparer(null, null));
  375. }
  376. public static bool StructuralComparableEquality<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  377. where T : IStructuralComparable {
  378. return StructuralCompare(context, x, y) == 0;
  379. }
  380. public static bool StructuralComparableInequality<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  381. where T : IStructuralComparable {
  382. return StructuralCompare(context, x, y) != 0;
  383. }
  384. public static bool StructuralComparableGreaterThan<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  385. where T : IStructuralComparable {
  386. return StructuralCompare(context, x, y) > 0;
  387. }
  388. public static bool StructuralComparableLessThan<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  389. where T : IStructuralComparable {
  390. return StructuralCompare(context, x, y) < 0;
  391. }
  392. public static bool StructuralComparableGreaterEqual<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  393. where T : IStructuralComparable {
  394. return StructuralCompare(context, x, y) >= 0;
  395. }
  396. public static bool StructuralComparableLessEqual<T>(CodeContext/*!*/ context, T x, [NotNull]T y)
  397. where T : IStructuralComparable {
  398. return StructuralCompare(context, x, y) <= 0;
  399. }
  400. [return: MaybeNotImplemented]
  401. public static object StructuralComparableEquality<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  402. where T : IStructuralComparable {
  403. if (!(y is T)) return NotImplementedType.Value;
  404. return ScriptingRuntimeHelpers.BooleanToObject(
  405. StructuralCompare(context, x, y) == 0
  406. );
  407. }
  408. [return: MaybeNotImplemented]
  409. public static object StructuralComparableInequality<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  410. where T : IStructuralComparable {
  411. if (!(y is T)) return NotImplementedType.Value;
  412. return ScriptingRuntimeHelpers.BooleanToObject(
  413. StructuralCompare(context, x, y) != 0
  414. );
  415. }
  416. [return: MaybeNotImplemented]
  417. public static object StructuralComparableGreaterThan<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  418. where T : IStructuralComparable {
  419. if (!(y is T)) return NotImplementedType.Value;
  420. return ScriptingRuntimeHelpers.BooleanToObject(
  421. StructuralCompare(context, x, y) > 0
  422. );
  423. }
  424. [return: MaybeNotImplemented]
  425. public static object StructuralComparableLessThan<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  426. where T : IStructuralComparable {
  427. if (!(y is T)) return NotImplementedType.Value;
  428. return ScriptingRuntimeHelpers.BooleanToObject(
  429. StructuralCompare(context, x, y) < 0
  430. );
  431. }
  432. [return: MaybeNotImplemented]
  433. public static object StructuralComparableGreaterEqual<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  434. where T : IStructuralComparable {
  435. if (!(y is T)) return NotImplementedType.Value;
  436. return ScriptingRuntimeHelpers.BooleanToObject(
  437. StructuralCompare(context, x, y) >= 0
  438. );
  439. }
  440. [return: MaybeNotImplemented]
  441. public static object StructuralComparableLessEqual<T>(CodeContext/*!*/ context, [NotNull]T x, object y)
  442. where T : IStructuralComparable {
  443. if (!(y is T)) return NotImplementedType.Value;
  444. return ScriptingRuntimeHelpers.BooleanToObject(
  445. StructuralCompare(context, x, y) <= 0
  446. );
  447. }
  448. [return: MaybeNotImplemented]
  449. public static object StructuralComparableEquality<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  450. where T : IStructuralComparable {
  451. if (!(y is T)) return NotImplementedType.Value;
  452. return ScriptingRuntimeHelpers.BooleanToObject(
  453. StructuralCompare(context, x, y) == 0
  454. );
  455. }
  456. [return: MaybeNotImplemented]
  457. public static object StructuralComparableInequality<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  458. where T : IStructuralComparable {
  459. if (!(y is T)) return NotImplementedType.Value;
  460. return ScriptingRuntimeHelpers.BooleanToObject(
  461. StructuralCompare(context, x, y) != 0
  462. );
  463. }
  464. [return: MaybeNotImplemented]
  465. public static object StructuralComparableGreaterThan<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  466. where T : IStructuralComparable {
  467. if (!(y is T)) return NotImplementedType.Value;
  468. return ScriptingRuntimeHelpers.BooleanToObject(
  469. // operator direction is reversed
  470. StructuralCompare(context, x, y) < 0
  471. );
  472. }
  473. [return: MaybeNotImplemented]
  474. public static object StructuralComparableLessThan<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  475. where T : IStructuralComparable {
  476. if (!(y is T)) return NotImplementedType.Value;
  477. return ScriptingRuntimeHelpers.BooleanToObject(
  478. // operator direction is reversed
  479. StructuralCompare(context, x, y) > 0
  480. );
  481. }
  482. [return: MaybeNotImplemented]
  483. public static object StructuralComparableGreaterEqual<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  484. where T : IStructuralComparable {
  485. if (!(y is T)) return NotImplementedType.Value;
  486. return ScriptingRuntimeHelpers.BooleanToObject(
  487. // operator direction is reversed
  488. StructuralCompare(context, x, y) <= 0
  489. );
  490. }
  491. [return: MaybeNotImplemented]
  492. public static object StructuralComparableLessEqual<T>(CodeContext/*!*/ context, object y, [NotNull]T x)
  493. where T : IStructuralComparable {
  494. if (!(y is T)) return NotImplementedType.Value;
  495. return ScriptingRuntimeHelpers.BooleanToObject(
  496. // operator direction is reversed
  497. StructuralCompare(context, x, y) >= 0
  498. );
  499. }
  500. // Comparison Helpers
  501. public static bool ComparableEquality<T>(T x, [NotNull]T y)
  502. where T : IComparable {
  503. return x.CompareTo(y) == 0;
  504. }
  505. public static bool ComparableInequality<T>(T x, [NotNull]T y)
  506. where T : IComparable {
  507. return x.CompareTo(y) != 0;
  508. }
  509. public static bool ComparableGreaterThan<T>(T x, [NotNull]T y)
  510. where T : IComparable {
  511. return x.CompareTo(y) > 0;
  512. }
  513. public static bool ComparableLessThan<T>(T x, [NotNull]T y)
  514. where T : IComparable {
  515. return x.CompareTo(y) < 0;
  516. }
  517. public static bool ComparableGreaterEqual<T>(T x, [NotNull]T y)
  518. where T : IComparable {
  519. return x.CompareTo(y) >= 0;
  520. }
  521. public static bool ComparableLessEqual<T>(T x, [NotNull]T y)
  522. where T : IComparable {
  523. return x.CompareTo(y) <= 0;
  524. }
  525. [return: MaybeNotImplemented]
  526. public static object ComparableEquality<T>([NotNull]T x, object y)
  527. where T : IComparable {
  528. if (!(y is T)) return NotImplementedType.Value;
  529. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) == 0);
  530. }
  531. [return: MaybeNotImplemented]
  532. public static object ComparableInequality<T>([NotNull]T x, object y)
  533. where T : IComparable {
  534. if (!(y is T)) return NotImplementedType.Value;
  535. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) != 0);
  536. }
  537. [return: MaybeNotImplemented]
  538. public static object ComparableGreaterThan<T>([NotNull]T x, object y)
  539. where T : IComparable {
  540. if (!(y is T)) return NotImplementedType.Value;
  541. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) > 0);
  542. }
  543. [return: MaybeNotImplemented]
  544. public static object ComparableLessThan<T>([NotNull]T x, object y)
  545. where T : IComparable {
  546. if (!(y is T)) return NotImplementedType.Value;
  547. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) < 0);
  548. }
  549. [return: MaybeNotImplemented]
  550. public static object ComparableGreaterEqual<T>([NotNull]T x, object y)
  551. where T : IComparable {
  552. if (!(y is T)) return NotImplementedType.Value;
  553. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) >= 0);
  554. }
  555. [return: MaybeNotImplemented]
  556. public static object ComparableLessEqual<T>([NotNull]T x, object y)
  557. where T : IComparable {
  558. if (!(y is T)) return NotImplementedType.Value;
  559. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) <= 0);
  560. }
  561. [return: MaybeNotImplemented]
  562. public static object ComparableEquality<T>(object y, [NotNull]T x)
  563. where T : IComparable {
  564. if (!(y is T)) return NotImplementedType.Value;
  565. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) == 0);
  566. }
  567. [return: MaybeNotImplemented]
  568. public static object ComparableInequality<T>(object y, [NotNull]T x)
  569. where T : IComparable {
  570. if (!(y is T)) return NotImplementedType.Value;
  571. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) != 0);
  572. }
  573. [return: MaybeNotImplemented]
  574. public static object ComparableGreaterThan<T>(object y, [NotNull]T x)
  575. where T : IComparable {
  576. if (!(y is T)) return NotImplementedType.Value;
  577. // operator direction is reversed
  578. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) < 0);
  579. }
  580. [return: MaybeNotImplemented]
  581. public static object ComparableLessThan<T>(object y, [NotNull]T x)
  582. where T : IComparable {
  583. if (!(y is T)) return NotImplementedType.Value;
  584. // operator direction is reversed
  585. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) > 0);
  586. }
  587. [return: MaybeNotImplemented]
  588. public static object ComparableGreaterEqual<T>(object y, [NotNull]T x)
  589. where T : IComparable {
  590. if (!(y is T)) return NotImplementedType.Value;
  591. // operator direction is reversed
  592. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) <= 0);
  593. }
  594. [return: MaybeNotImplemented]
  595. public static object ComparableLessEqual<T>(object y, [NotNull]T x)
  596. where T : IComparable {
  597. if (!(y is T)) return NotImplementedType.Value;
  598. // operator direction is reversed
  599. return ScriptingRuntimeHelpers.BooleanToObject(x.CompareTo(y) >= 0);
  600. }
  601. #endregion
  602. /// <summary>
  603. /// Provides the implementation of __enter__ for objects which implement IDisposable.
  604. /// </summary>
  605. public static object EnterMethod(IDisposable/*!*/ self) {
  606. return self;
  607. }
  608. /// <summary>
  609. /// Provides the implementation of __exit__ for objects which implement IDisposable.
  610. /// </summary>
  611. public static void ExitMethod(IDisposable/*!*/ self, object exc_type, object exc_value, object exc_back) {
  612. self.Dispose();
  613. }
  614. [PropertyMethod, StaticExtensionMethod]
  615. public static List/*!*/ Get__all__<T>(CodeContext/*!*/ context) {
  616. Debug.Assert(typeof(T).IsSealed() && typeof(T).IsAbstract(), "__all__ should only be produced for static members");
  617. PythonType pt = DynamicHelpers.GetPythonTypeFromType(typeof(T));
  618. List names = new List();
  619. foreach (string name in pt.GetMemberNames(context)) {
  620. object res;
  621. if (IsStaticTypeMemberInAll(context, pt, name, out res)) {
  622. names.AddNoLock(name);
  623. }
  624. }
  625. return names;
  626. }
  627. /// <summary>
  628. /// Determines if a type member can be imported. This is used to treat static types like modules.
  629. /// </summary>
  630. private static bool IsStaticTypeMemberInAll(CodeContext/*!*/ context, PythonType/*!*/ pt, string name, out object res) {
  631. PythonTypeSlot pts;
  632. res = null;
  633. if (pt.TryResolveSlot(context, name, out pts)) {
  634. if (name == "__doc__" || name == "__class__") {
  635. // these exist but we don't want to clobber __doc__ on import * or bring in __class__
  636. return false;
  637. } else if (pts is ReflectedGetterSetter) {
  638. // property or indexer, these fetch the value at runtime, the user needs to explicitly
  639. // import them using from type import property
  640. return false;
  641. }
  642. ReflectedField rf = pts as ReflectedField;
  643. if (rf != null && !rf._info.IsInitOnly && !rf._info.IsLiteral) {
  644. // only bring in read-only fields, if the value can change the user needs to explicitly
  645. // import by name
  646. return false;
  647. }
  648. BuiltinMethodDescriptor method = pts as BuiltinMethodDescriptor;
  649. if (method != null && (!method.DeclaringType.IsSealed() || !method.DeclaringType.IsAbstract())) {
  650. // inherited object member on a static class (GetHashCode, Equals, etc...)
  651. return false;
  652. }
  653. BuiltinFunction bf = pts as BuiltinFunction;
  654. if (bf != null && (!bf.DeclaringType.IsSealed() || !bf.DeclaringType.IsAbstract())) {
  655. // __new__/ReferenceEquals inherited from object
  656. return false;
  657. }
  658. if (pts.TryGetValue(context, null, pt, out res)) {
  659. return true;
  660. }
  661. }
  662. res = null;
  663. return false;
  664. }
  665. #region Contains
  666. /// <summary>
  667. /// Implements __contains__ for types implementing IEnumerable of T.
  668. /// </summary>
  669. public static bool ContainsGenericMethod<T>(CodeContext/*!*/ context, IEnumerable<T> enumerable, T value) {
  670. foreach(T item in enumerable) {
  671. if (PythonOps.EqualRetBool(context, item, value)) {
  672. return true;
  673. }
  674. }
  675. return false;
  676. }
  677. /// <summary>
  678. /// Implements __contains__ for types implementing IEnumerable
  679. /// </summary>
  680. public static bool ContainsMethod(CodeContext/*!*/ context, IEnumerable enumerable, object value) {
  681. IEnumerator ie = enumerable.GetEnumerator();
  682. while (ie.MoveNext()) {
  683. if (PythonOps.EqualRetBool(context, ie.Current, value)) {
  684. return true;
  685. }
  686. }
  687. return false;
  688. }
  689. /// <summary>
  690. /// Implements __contains__ for types implementing IEnumerable of T.
  691. /// </summary>
  692. public static bool ContainsGenericMethodIEnumerator<T>(CodeContext/*!*/ context, IEnumerator<T> enumerator, T value) {
  693. while (enumerator.MoveNext()) {
  694. if (PythonOps.EqualRetBool(context, enumerator.Current, value)) {
  695. return true;
  696. }
  697. }
  698. return false;
  699. }
  700. /// <summary>
  701. /// Implements __contains__ for types implementing IEnumerable
  702. /// </summary>
  703. public static bool ContainsMethodIEnumerator(CodeContext/*!*/ context, IEnumerator enumerator, object value) {
  704. while (enumerator.MoveNext()) {
  705. if (PythonOps.EqualRetBool(context, enumerator.Current, value)) {
  706. return true;
  707. }
  708. }
  709. return false;
  710. }
  711. #endregion
  712. #if FEATURE_SERIALIZATION
  713. /// <summary>
  714. /// Implements __reduce_ex__ for .NET types which are serializable. This uses the .NET
  715. /// serializer to get a string of raw data which can be serialized.
  716. /// </summary>
  717. public static PythonTuple SerializeReduce(CodeContext/*!*/ context, object/*!*/ self, int protocol) {
  718. PythonTuple data = ClrModule.Serialize(self);
  719. object deserializeNew;
  720. bool res = PythonContext.GetContext(context).ClrModule.__dict__.TryGetValue(
  721. "Deserialize",
  722. out deserializeNew
  723. );
  724. Debug.Assert(res);
  725. return PythonTuple.MakeTuple(
  726. deserializeNew, // function to call, clr.DeserializeNew
  727. data, // data to pass to it - our type & the raw data from the .NET serializer
  728. null // state, unused
  729. );
  730. }
  731. #endif
  732. internal const string ObjectNewNoParameters = "object.__new__() takes no parameters";
  733. internal static void CheckNewArgs(CodeContext context, IDictionary<object, object> dict, object[] args, PythonType pt) {
  734. if (((args != null && args.Length > 0) || (dict != null && dict.Count > 0))) {
  735. bool hasObjectInit = pt.HasObjectInit(context);
  736. bool hasObjectNew = pt.HasObjectNew(context);
  737. if (hasObjectInit) {
  738. throw PythonOps.TypeError(ObjectNewNoParameters);
  739. } else if (!hasObjectNew && !hasObjectInit) {
  740. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, ObjectNewNoParameters);
  741. }
  742. }
  743. }
  744. internal static void CheckInitArgs(CodeContext context, IDictionary<object, object> dict, object[] args, object self) {
  745. if (((args != null && args.Length > 0) || (dict != null && dict.Count > 0))) {
  746. PythonType pt = DynamicHelpers.GetPythonType(self);
  747. bool hasObjectInit = pt.HasObjectInit(context);
  748. bool hasObjectNew = pt.HasObjectNew(context);
  749. // NoneType seems to get some special treatment (None.__init__('abc') works)
  750. if (hasObjectNew && self != null) {
  751. throw PythonOps.TypeError("object.__init__() takes no parameters");
  752. }
  753. }
  754. }
  755. private static BuiltinMethodDescriptor GetInitMethod() {
  756. PythonTypeSlot pts;
  757. TypeCache.Object.TryResolveSlot(DefaultContext.Default, "__init__", out pts);
  758. Debug.Assert(pts != null);
  759. return (BuiltinMethodDescriptor)pts;
  760. }
  761. private static BuiltinFunction CreateFunction(string name, params string[] methodNames) {
  762. MethodBase[] methods = new MethodBase[methodNames.Length];
  763. for (int i = 0; i < methods.Length; i++) {
  764. methods[i] = typeof(InstanceOps).GetMethod(methodNames[i]);
  765. }
  766. return BuiltinFunction.MakeFunction(name, methods, typeof(object));
  767. }
  768. private static void GetKeywordArgs(IDictionary<object, object> dict, object[] args, out object[] finalArgs, out string[] names) {
  769. finalArgs = new object[args.Length + dict.Count];
  770. Array.Copy(args, finalArgs, args.Length);
  771. names = new string[dict.Count];
  772. int i = 0;
  773. foreach (KeyValuePair<object, object> kvp in dict) {
  774. names[i] = (string)kvp.Key;
  775. finalArgs[i + args.Length] = kvp.Value;
  776. i++;
  777. }
  778. }
  779. }
  780. }