PageRenderTime 105ms CodeModel.GetById 30ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

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