/DLR_Main/Languages/IronPython/IronPython/Runtime/Operations/PythonOps.cs
C# | 1196 lines | 883 code | 208 blank | 105 comment | 332 complexity | feb72380f521425e952eaa41adc94b22 MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if !CLR2
- using System.Linq.Expressions;
- using System.Numerics;
- using Microsoft.Scripting.Ast;
- #else
- using Microsoft.Scripting.Ast;
- using Microsoft.Scripting.Math;
- using Complex = Microsoft.Scripting.Math.Complex64;
- #endif
-
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Dynamic;
- using System.IO;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Threading;
-
- using Microsoft.Scripting;
- using Microsoft.Scripting.Actions;
- using Microsoft.Scripting.Generation;
- using Microsoft.Scripting.Hosting.Providers;
- using Microsoft.Scripting.Hosting.Shell;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
-
- using IronPython.Compiler;
- using IronPython.Hosting;
- using IronPython.Modules;
- using IronPython.Runtime.Binding;
- using IronPython.Runtime.Exceptions;
- using IronPython.Runtime.Types;
-
- #if !SILVERLIGHT
- using System.ComponentModel;
- #endif
-
- namespace IronPython.Runtime.Operations {
-
- /// <summary>
- /// Contains functions that are called directly from
- /// generated code to perform low-level runtime functionality.
- /// </summary>
- public static partial class PythonOps {
- #region Shared static data
-
- [ThreadStatic]
- private static List<object> InfiniteRepr;
-
- // The "current" exception on this thread that will be returned via sys.exc_info()
- [ThreadStatic]
- internal static Exception RawException;
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
- public static readonly PythonTuple EmptyTuple = PythonTuple.EMPTY;
- private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
-
- #endregion
-
- public static BigInteger MakeIntegerFromHex(string s) {
- return LiteralParser.ParseBigInteger(s, 16);
- }
-
- public static PythonDictionary MakeDict(int size) {
- return new PythonDictionary(size);
- }
-
- public static PythonDictionary MakeEmptyDict() {
- return new PythonDictionary(EmptyDictionaryStorage.Instance);
- }
-
- /// <summary>
- /// Creates a new dictionary extracting the keys and values from the
- /// provided data array. Keys/values are adjacent in the array with
- /// the value coming first.
- /// </summary>
- public static PythonDictionary MakeDictFromItems(params object[] data) {
- return new PythonDictionary(new CommonDictionaryStorage(data, false));
- }
-
- public static PythonDictionary MakeConstantDict(object items) {
- return new PythonDictionary((ConstantDictionaryStorage)items);
- }
-
- public static object MakeConstantDictStorage(params object[] data) {
- return new ConstantDictionaryStorage(new CommonDictionaryStorage(data, false));
- }
-
- public static SetCollection MakeSet(params object[] items) {
- return new SetCollection(items);
- }
-
- public static SetCollection MakeEmptySet() {
- return new SetCollection();
- }
-
- /// <summary>
- /// Creates a new dictionary extracting the keys and values from the
- /// provided data array. Keys/values are adjacent in the array with
- /// the value coming first.
- /// </summary>
- public static PythonDictionary MakeHomogeneousDictFromItems(object[] data) {
- return new PythonDictionary(new CommonDictionaryStorage(data, true));
- }
-
- public static bool IsCallable(CodeContext/*!*/ context, object o) {
- // This tells if an object can be called, but does not make a claim about the parameter list.
- // In 1.x, we could check for certain interfaces like ICallable*, but those interfaces were deprecated
- // in favor of dynamic sites.
- // This is difficult to infer because we'd need to simulate the entire callbinder, which can include
- // looking for [SpecialName] call methods and checking for a rule from IDynamicMetaObjectProvider. But even that wouldn't
- // be complete since sites require the argument list of the call, and we only have the instance here.
- // Thus check a dedicated IsCallable operator. This lets each object describe if it's callable.
-
-
- // Invoke Operator.IsCallable on the object.
- return PythonContext.GetContext(context).IsCallable(o);
- }
-
- public static bool IsTrue(object o) {
- return Converter.ConvertToBoolean(o);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
- public static List<object> GetReprInfinite() {
- if (InfiniteRepr == null) {
- InfiniteRepr = new List<object>();
- }
- return InfiniteRepr;
- }
-
- [LightThrowing]
- internal static object LookupEncodingError(CodeContext/*!*/ context, string name) {
- Dictionary<string, object> errorHandlers = PythonContext.GetContext(context).ErrorHandlers;
- lock (errorHandlers) {
- if (errorHandlers.ContainsKey(name))
- return errorHandlers[name];
- else
- return LightExceptions.Throw(PythonOps.LookupError("unknown error handler name '{0}'", name));
- }
- }
-
- internal static void RegisterEncodingError(CodeContext/*!*/ context, string name, object handler) {
- Dictionary<string, object> errorHandlers = PythonContext.GetContext(context).ErrorHandlers;
-
- lock (errorHandlers) {
- if (!PythonOps.IsCallable(context, handler))
- throw PythonOps.TypeError("handler must be callable");
-
- errorHandlers[name] = handler;
- }
- }
-
- internal static PythonTuple LookupEncoding(CodeContext/*!*/ context, string encoding) {
- PythonContext.GetContext(context).EnsureEncodings();
-
- List<object> searchFunctions = PythonContext.GetContext(context).SearchFunctions;
- string normalized = encoding.ToLower().Replace(' ', '-');
- if (normalized.IndexOf(Char.MinValue) != -1) {
- throw PythonOps.TypeError("lookup string cannot contain null character");
- }
- lock (searchFunctions) {
- for (int i = 0; i < searchFunctions.Count; i++) {
- object res = PythonCalls.Call(context, searchFunctions[i], normalized);
- if (res != null) return (PythonTuple)res;
- }
- }
-
- throw PythonOps.LookupError("unknown encoding: {0}", encoding);
- }
-
- internal static void RegisterEncoding(CodeContext/*!*/ context, object search_function) {
- if (!PythonOps.IsCallable(context, search_function))
- throw PythonOps.TypeError("search_function must be callable");
-
- List<object> searchFunctions = PythonContext.GetContext(context).SearchFunctions;
-
- lock (searchFunctions) {
- searchFunctions.Add(search_function);
- }
- }
-
- internal static string GetPythonTypeName(object obj) {
- OldInstance oi = obj as OldInstance;
- if (oi != null) return oi._class._name.ToString();
- else return PythonTypeOps.GetName(obj);
- }
-
- public static string Repr(CodeContext/*!*/ context, object o) {
- if (o == null) return "None";
-
- string s;
- if ((s = o as string) != null) return StringOps.__repr__(s);
- if (o is int) return Int32Ops.__repr__((int)o);
- if (o is long) return ((long)o).ToString() + "L";
-
- // could be a container object, we need to detect recursion, but only
- // for our own built-in types that we're aware of. The user can setup
- // infinite recursion in their own class if they want.
- ICodeFormattable f = o as ICodeFormattable;
- if (f != null) {
- return f.__repr__(context);
- }
-
- PerfTrack.NoteEvent(PerfTrack.Categories.Temporary, "Repr " + o.GetType().FullName);
-
- return PythonContext.InvokeUnaryOperator(context, UnaryOperators.Repr, o) as string;
- }
-
- public static List<object> GetAndCheckInfinite(object o) {
- List<object> infinite = GetReprInfinite();
- foreach (object o2 in infinite) {
- if (o == o2) {
- return null;
- }
- }
- return infinite;
- }
-
- public static string ToString(object o) {
- return ToString(DefaultContext.Default, o);
- }
-
- public static string ToString(CodeContext/*!*/ context, object o) {
- string x = o as string;
- PythonType dt;
- OldClass oc;
- if (x != null) return x;
- if (o == null) return "None";
- if (o is double) return DoubleOps.__str__(context, (double)o);
- if ((dt = o as PythonType) != null) return dt.__repr__(DefaultContext.Default);
- if ((oc = o as OldClass) != null) return oc.ToString();
-
- object value = PythonContext.InvokeUnaryOperator(context, UnaryOperators.String, o);
- string ret = value as string;
- if (ret == null) {
- Extensible<string> es = value as Extensible<string>;
- if (es == null) {
- throw PythonOps.TypeError("expected str, got {0} from __str__", PythonTypeOps.GetName(value));
- }
-
- ret = es.Value;
- }
-
- return ret;
- }
-
- public static string FormatString(CodeContext context, string str, object data) {
- return new StringFormatter(context, str, data).Format();
- }
-
- public static string FormatUnicode(CodeContext context, string str, object data) {
- return new StringFormatter(context, str, data, true).Format();
- }
-
- public static object Plus(object o) {
- object ret;
-
- if (o is int) return o;
- else if (o is double) return o;
- else if (o is BigInteger) return o;
- else if (o is Complex) return o;
- else if (o is long) return o;
- else if (o is float) return o;
- else if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? 1 : 0);
-
- if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__pos__", out ret) &&
- ret != NotImplementedType.Value) {
- return ret;
- }
-
- throw PythonOps.TypeError("bad operand type for unary +");
- }
-
- public static object Negate(object o) {
- if (o is int) return Int32Ops.Negate((int)o);
- else if (o is double) return DoubleOps.Negate((double)o);
- else if (o is long) return Int64Ops.Negate((long)o);
- else if (o is BigInteger) return BigIntegerOps.Negate((BigInteger)o);
- else if (o is Complex) return -(Complex)o;
- else if (o is float) return DoubleOps.Negate((float)o);
- else if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? -1 : 0);
-
- object ret;
- if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__neg__", out ret) &&
- ret != NotImplementedType.Value) {
- return ret;
- }
-
- throw PythonOps.TypeError("bad operand type for unary -");
- }
-
- public static bool IsSubClass(PythonType/*!*/ c, PythonType/*!*/ typeinfo) {
- Assert.NotNull(c, typeinfo);
-
- if (c.OldClass != null) {
- return typeinfo.__subclasscheck__(c.OldClass);
- }
-
- return typeinfo.__subclasscheck__(c);
- }
-
- public static bool IsSubClass(CodeContext context, PythonType c, object typeinfo) {
- if (c == null) throw PythonOps.TypeError("issubclass: arg 1 must be a class");
- if (typeinfo == null) throw PythonOps.TypeError("issubclass: arg 2 must be a class");
-
- PythonTuple pt = typeinfo as PythonTuple;
- PythonContext pyContext = PythonContext.GetContext(context);
- if (pt != null) {
- // Recursively inspect nested tuple(s)
- foreach (object o in pt) {
- try {
- FunctionPushFrame(pyContext);
- if (IsSubClass(context, c, o)) {
- return true;
- }
- } finally {
- FunctionPopFrame();
- }
- }
- return false;
- }
-
- OldClass oc = typeinfo as OldClass;
- if (oc != null) {
- return c.IsSubclassOf(oc.TypeObject);
- }
-
- Type t = typeinfo as Type;
- if (t != null) {
- typeinfo = DynamicHelpers.GetPythonTypeFromType(t);
- }
-
- object bases;
- PythonType dt = typeinfo as PythonType;
- if (dt == null) {
- if (!PythonOps.TryGetBoundAttr(typeinfo, "__bases__", out bases)) {
- //!!! deal with classes w/ just __bases__ defined.
- throw PythonOps.TypeErrorForBadInstance("issubclass(): {0} is not a class nor a tuple of classes", typeinfo);
- }
-
- IEnumerator ie = PythonOps.GetEnumerator(bases);
- while (ie.MoveNext()) {
- PythonType baseType = ie.Current as PythonType;
-
- if (baseType == null) {
- OldClass ocType = ie.Current as OldClass;
- if (ocType == null) {
- continue;
- }
-
- baseType = ocType.TypeObject;
- }
-
- if (c.IsSubclassOf(baseType)) return true;
- }
- return false;
- }
-
- return IsSubClass(c, dt);
- }
-
- public static bool IsInstance(object o, PythonType typeinfo) {
- if (typeinfo.__instancecheck__(o)) {
- return true;
- }
-
- return IsInstanceDynamic(o, typeinfo, DynamicHelpers.GetPythonType(o));
- }
-
- public static bool IsInstance(CodeContext context, object o, PythonTuple typeinfo) {
- PythonContext pyContext = PythonContext.GetContext(context);
- foreach (object type in typeinfo) {
- try {
- PythonOps.FunctionPushFrame(pyContext);
- if (type is PythonType) {
- if (IsInstance(o, (PythonType)type)) {
- return true;
- }
- } else if (type is PythonTuple) {
- if (IsInstance(context, o, (PythonTuple)type)) {
- return true;
- }
- } else if (IsInstance(context, o, type)) {
- return true;
- }
- } finally {
- PythonOps.FunctionPopFrame();
- }
- }
- return false;
- }
-
- public static bool IsInstance(CodeContext context, object o, object typeinfo) {
- if (typeinfo == null) throw PythonOps.TypeError("isinstance: arg 2 must be a class, type, or tuple of classes and types");
-
- PythonTuple tt = typeinfo as PythonTuple;
- if (tt != null) {
- return IsInstance(context, o, tt);
- }
-
- if (typeinfo is OldClass) {
- // old instances are strange - they all share a common type
- // of instance but they can "be subclasses" of other
- // OldClass's. To check their types we need the actual
- // instance.
- OldInstance oi = o as OldInstance;
- if (oi != null) return oi._class.IsSubclassOf(typeinfo);
- }
-
- PythonType odt = DynamicHelpers.GetPythonType(o);
- if (IsSubClass(context, odt, typeinfo)) {
- return true;
- }
-
- return IsInstanceDynamic(o, typeinfo);
- }
-
- private static bool IsInstanceDynamic(object o, object typeinfo) {
- return IsInstanceDynamic(o, typeinfo, DynamicHelpers.GetPythonType(o));
- }
-
- private static bool IsInstanceDynamic(object o, object typeinfo, PythonType odt) {
- if (o is IPythonObject || o is OldInstance) {
- object cls;
- if (PythonOps.TryGetBoundAttr(o, "__class__", out cls) &&
- (!object.ReferenceEquals(odt, cls))) {
- return IsSubclassSlow(cls, typeinfo);
- }
- }
- return false;
- }
-
- private static bool IsSubclassSlow(object cls, object typeinfo) {
- Debug.Assert(typeinfo != null);
- if (cls == null) return false;
-
- // Same type
- if (cls.Equals(typeinfo)) {
- return true;
- }
-
- // Get bases
- object bases;
- if (!PythonOps.TryGetBoundAttr(cls, "__bases__", out bases)) {
- return false; // no bases, cannot be subclass
- }
- PythonTuple tbases = bases as PythonTuple;
- if (tbases == null) {
- return false; // not a tuple, cannot be subclass
- }
-
- foreach (object baseclass in tbases) {
- if (IsSubclassSlow(baseclass, typeinfo)) return true;
- }
-
- return false;
- }
-
- public static object OnesComplement(object o) {
- if (o is int) return ~(int)o;
- if (o is long) return ~(long)o;
- if (o is BigInteger) return ~((BigInteger)o);
- if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? -2 : -1);
-
- object ret;
- if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__invert__", out ret) &&
- ret != NotImplementedType.Value)
- return ret;
-
-
- throw PythonOps.TypeError("bad operand type for unary ~");
- }
-
- public static bool Not(object o) {
- return !IsTrue(o);
- }
-
- public static object Is(object x, object y) {
- return x == y ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static bool IsRetBool(object x, object y) {
- return x == y;
- }
-
- public static object IsNot(object x, object y) {
- return x != y ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static bool IsNotRetBool(object x, object y) {
- return x != y;
- }
-
- internal delegate T MultiplySequenceWorker<T>(T self, int count);
-
- /// <summary>
- /// Wraps up all the semantics of multiplying sequences so that all of our sequences
- /// don't duplicate the same logic. When multiplying sequences we need to deal with
- /// only multiplying by valid sequence types (ints, not floats), support coercion
- /// to integers if the type supports it, not multiplying by None, and getting the
- /// right semantics for multiplying by negative numbers and 1 (w/ and w/o subclasses).
- ///
- /// This function assumes that it is only called for case where count is not implicitly
- /// coercible to int so that check is skipped.
- /// </summary>
- internal static object MultiplySequence<T>(MultiplySequenceWorker<T> multiplier, T sequence, Index count, bool isForward) {
- if (isForward && count != null) {
- object ret;
- if (PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default, count.Value, sequence, "__rmul__", out ret)) {
- if (ret != NotImplementedType.Value) return ret;
- }
- }
-
- int icount = GetSequenceMultiplier(sequence, count.Value);
-
- if (icount < 0) icount = 0;
- return multiplier(sequence, icount);
- }
-
- internal static int GetSequenceMultiplier(object sequence, object count) {
- int icount;
- if (!Converter.TryConvertToIndex(count, out icount)) {
- PythonTuple pt = null;
- if (count is OldInstance || !DynamicHelpers.GetPythonType(count).IsSystemType) {
- pt = Builtin.TryCoerce(DefaultContext.Default, count, sequence) as PythonTuple;
- }
-
- if (pt == null || !Converter.TryConvertToIndex(pt[0], out icount)) {
- throw TypeError("can't multiply sequence by non-int of type '{0}'", PythonTypeOps.GetName(count));
- }
- }
- return icount;
- }
-
- public static object Equal(CodeContext/*!*/ context, object x, object y) {
- PythonContext pc = PythonContext.GetContext(context);
- return pc.EqualSite.Target(pc.EqualSite, x, y);
- }
-
- public static bool EqualRetBool(object x, object y) {
- //TODO just can't seem to shake these fast paths
- if (x is int && y is int) { return ((int)x) == ((int)y); }
- if (x is string && y is string) { return ((string)x).Equals((string)y); }
-
- return DynamicHelpers.GetPythonType(x).EqualRetBool(x, y);
- }
-
- public static bool EqualRetBool(CodeContext/*!*/ context, object x, object y) {
- // TODO: use context
-
- //TODO just can't seem to shake these fast paths
- if (x is int && y is int) { return ((int)x) == ((int)y); }
- if (x is string && y is string) { return ((string)x).Equals((string)y); }
-
- return DynamicHelpers.GetPythonType(x).EqualRetBool(x, y);
- }
-
- public static int Compare(object x, object y) {
- return Compare(DefaultContext.Default, x, y);
- }
-
- public static int Compare(CodeContext/*!*/ context, object x, object y) {
- if (x == y) return 0;
-
- return DynamicHelpers.GetPythonType(x).Compare(x, y);
- }
-
- public static object CompareEqual(int res) {
- return res == 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static object CompareNotEqual(int res) {
- return res == 0 ? ScriptingRuntimeHelpers.False : ScriptingRuntimeHelpers.True;
- }
-
- public static object CompareGreaterThan(int res) {
- return res > 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static object CompareGreaterThanOrEqual(int res) {
- return res >= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static object CompareLessThan(int res) {
- return res < 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static object CompareLessThanOrEqual(int res) {
- return res <= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
- }
-
- public static bool CompareTypesEqual(CodeContext/*!*/ context, object x, object y) {
- if (x == null && y == null) return true;
- if (x == null) return false;
- if (y == null) return false;
-
- if (DynamicHelpers.GetPythonType(x) == DynamicHelpers.GetPythonType(y)) {
- // avoid going to the ID dispenser if we have the same types...
- return x == y;
- }
-
- return PythonOps.CompareTypesWorker(context, false, x, y) == 0;
- }
-
- public static bool CompareTypesNotEqual(CodeContext/*!*/ context, object x, object y) {
- return PythonOps.CompareTypesWorker(context, false, x, y) != 0;
- }
-
- public static bool CompareTypesGreaterThan(CodeContext/*!*/ context, object x, object y) {
- return PythonOps.CompareTypes(context, x, y) > 0;
- }
-
- public static bool CompareTypesLessThan(CodeContext/*!*/ context, object x, object y) {
- return PythonOps.CompareTypes(context, x, y) < 0;
- }
-
- public static bool CompareTypesGreaterThanOrEqual(CodeContext/*!*/ context, object x, object y) {
- return PythonOps.CompareTypes(context, x, y) >= 0;
- }
-
- public static bool CompareTypesLessThanOrEqual(CodeContext/*!*/ context, object x, object y) {
- return PythonOps.CompareTypes(context, x, y) <= 0;
- }
-
- public static int CompareTypesWorker(CodeContext/*!*/ context, bool shouldWarn, object x, object y) {
- if (x == null && y == null) return 0;
- if (x == null) return -1;
- if (y == null) return 1;
-
- string name1, name2;
- int diff;
-
- if (DynamicHelpers.GetPythonType(x) != DynamicHelpers.GetPythonType(y)) {
- if (shouldWarn && PythonContext.GetContext(context).PythonOptions.WarnPython30) {
- PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "comparing unequal types not supported in 3.x");
- }
-
- if (x.GetType() == typeof(OldInstance)) {
- name1 = ((OldInstance)x)._class.Name;
- if (y.GetType() == typeof(OldInstance)) {
- name2 = ((OldInstance)y)._class.Name;
- } else {
- // old instances are always less than new-style classes
- return -1;
- }
- } else if (y.GetType() == typeof(OldInstance)) {
- // old instances are always less than new-style classes
- return 1;
- } else {
- name1 = PythonTypeOps.GetName(x);
- name2 = PythonTypeOps.GetName(y);
- }
- diff = String.CompareOrdinal(name1, name2);
- if (diff == 0) {
- // if the types are different but have the same name compare based upon their types.
- diff = (int)(IdDispenser.GetId(DynamicHelpers.GetPythonType(x)) - IdDispenser.GetId(DynamicHelpers.GetPythonType(y)));
- }
- } else {
- diff = (int)(IdDispenser.GetId(x) - IdDispenser.GetId(y));
- }
-
- if (diff < 0) return -1;
- if (diff == 0) return 0;
- return 1;
- }
-
- public static int CompareTypes(CodeContext/*!*/ context, object x, object y) {
- return CompareTypesWorker(context, true, x, y);
- }
-
- public static object GreaterThanHelper(CodeContext/*!*/ context, object self, object other) {
- return InternalCompare(context, PythonOperationKind.GreaterThan, self, other);
- }
-
- public static object LessThanHelper(CodeContext/*!*/ context, object self, object other) {
- return InternalCompare(context, PythonOperationKind.LessThan, self, other);
- }
-
- public static object GreaterThanOrEqualHelper(CodeContext/*!*/ context, object self, object other) {
- return InternalCompare(context, PythonOperationKind.GreaterThanOrEqual, self, other);
- }
-
- public static object LessThanOrEqualHelper(CodeContext/*!*/ context, object self, object other) {
- return InternalCompare(context, PythonOperationKind.LessThanOrEqual, self, other);
- }
-
- internal static object InternalCompare(CodeContext/*!*/ context, PythonOperationKind op, object self, object other) {
- object ret;
- if (PythonTypeOps.TryInvokeBinaryOperator(context, self, other, Symbols.OperatorToSymbol(op), out ret))
- return ret;
-
- return NotImplementedType.Value;
- }
-
- public static int CompareToZero(object value) {
- double val;
- if (Converter.TryConvertToDouble(value, out val)) {
- if (val > 0) return 1;
- if (val < 0) return -1;
- return 0;
- }
- throw PythonOps.TypeErrorForBadInstance("an integer is required (got {0})", value);
- }
-
- public static int CompareArrays(object[] data0, int size0, object[] data1, int size1) {
- int size = Math.Min(size0, size1);
- for (int i = 0; i < size; i++) {
- int c = PythonOps.Compare(data0[i], data1[i]);
- if (c != 0) return c;
- }
- if (size0 == size1) return 0;
- return size0 > size1 ? +1 : -1;
- }
-
- public static int CompareArrays(object[] data0, int size0, object[] data1, int size1, IComparer comparer) {
- int size = Math.Min(size0, size1);
- for (int i = 0; i < size; i++) {
- int c = comparer.Compare(data0[i], data1[i]);
- if (c != 0) return c;
- }
- if (size0 == size1) return 0;
- return size0 > size1 ? +1 : -1;
- }
-
- public static bool ArraysEqual(object[] data0, int size0, object[] data1, int size1) {
- if (size0 != size1) {
- return false;
- }
- for (int i = 0; i < size0; i++) {
- if (data0[i] != null) {
- if (!EqualRetBool(data0[i], data1[i])) {
- return false;
- }
- } else if (data1[i] != null) {
- return false;
- }
- }
- return true;
- }
-
- public static bool ArraysEqual(object[] data0, int size0, object[] data1, int size1, IEqualityComparer comparer) {
- if (size0 != size1) {
- return false;
- }
- for (int i = 0; i < size0; i++) {
- if (data0[i] != null) {
- if (!comparer.Equals(data0[i], data1[i])) {
- return false;
- }
- } else if (data1[i] != null) {
- return false;
- }
- }
- return true;
- }
-
- public static object PowerMod(CodeContext/*!*/ context, object x, object y, object z) {
- object ret;
- if (z == null) {
- return PythonContext.GetContext(context).Operation(PythonOperationKind.Power, x, y);
- }
- if (x is int && y is int && z is int) {
- ret = Int32Ops.Power((int)x, (int)y, (int)z);
- if (ret != NotImplementedType.Value) return ret;
- } else if (x is BigInteger) {
- ret = BigIntegerOps.Power((BigInteger)x, y, z);
- if (ret != NotImplementedType.Value) return ret;
- }
-
- if (x is Complex || y is Complex || z is Complex) {
- throw PythonOps.ValueError("complex modulo");
- }
-
- if (PythonTypeOps.TryInvokeTernaryOperator(context, x, y, z, "__pow__", out ret)) {
- if (ret != NotImplementedType.Value) {
- return ret;
- } else if (!IsNumericObject(y) || !IsNumericObject(z)) {
- // special error message in this case...
- throw TypeError("pow() 3rd argument not allowed unless all arguments are integers");
- }
- }
-
- throw PythonOps.TypeErrorForBinaryOp("power with modulus", x, y);
- }
-
- public static long Id(object o) {
- return IdDispenser.GetId(o);
- }
-
- public static string HexId(object o) {
- return string.Format("0x{0:X16}", Id(o));
- }
-
- // For hash operators, it's essential that:
- // Cmp(x,y)==0 implies hash(x) == hash(y)
- //
- // Equality is a language semantic determined by the Python's numerical Compare() ops
- // in IronPython.Runtime.Operations namespaces.
- // For example, the CLR compares float(1.0) and int32(1) as different, but Python
- // compares them as equal. So Hash(1.0f) and Hash(1) must be equal.
- //
- // Python allows an equality relationship between int, double, BigInteger, and complex.
- // So each of these hash functions must be aware of their possible equality relationships
- // and hash appropriately.
- //
- // Types which differ in hashing from .NET have __hash__ functions defined in their
- // ops classes which do the appropriate hashing.
- public static int Hash(CodeContext/*!*/ context, object o) {
- return PythonContext.Hash(o);
- }
-
- public static object Hex(object o) {
- if (o is int) return Int32Ops.__hex__((int)o);
- else if (o is BigInteger) return BigIntegerOps.__hex__((BigInteger)o);
-
- object hex;
- if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
- o,
- "__hex__",
- out hex)) {
- if (!(hex is string) && !(hex is ExtensibleString))
- throw PythonOps.TypeError("hex expected string type as return, got '{0}'", PythonTypeOps.GetName(hex));
-
- return hex;
- }
- throw TypeError("hex() argument cannot be converted to hex");
- }
-
- public static object Oct(object o) {
- if (o is int) {
- return Int32Ops.__oct__((int)o);
- } else if (o is BigInteger) {
- return BigIntegerOps.__oct__((BigInteger)o);
- }
-
- object octal;
-
- if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
- o,
- "__oct__",
- out octal)) {
- if (!(octal is string) && !(octal is ExtensibleString))
- throw PythonOps.TypeError("hex expected string type as return, got '{0}'", PythonTypeOps.GetName(octal));
-
- return octal;
- }
- throw TypeError("oct() argument cannot be converted to octal");
- }
-
- public static int Length(object o) {
- string s = o as string;
- if (s != null) {
- return s.Length;
- }
-
- object[] os = o as object[];
- if (os != null) {
- return os.Length;
- }
-
- object len = PythonContext.InvokeUnaryOperator(DefaultContext.Default, UnaryOperators.Length, o, "len() of unsized object");
-
- int res;
- if (len is int) {
- res = (int)len;
- } else {
- res = Converter.ConvertToInt32(len);
- }
-
- if (res < 0) {
- throw PythonOps.ValueError("__len__ should return >= 0, got {0}", res);
- }
- return res;
- }
-
- public static object CallWithContext(CodeContext/*!*/ context, object func, params object[] args) {
- return PythonCalls.Call(context, func, args);
- }
-
- /// <summary>
- /// Supports calling of functions that require an explicit 'this'
- /// Currently, we check if the function object implements the interface
- /// that supports calling with 'this'. If not, the 'this' object is dropped
- /// and a normal call is made.
- /// </summary>
- public static object CallWithContextAndThis(CodeContext/*!*/ context, object func, object instance, params object[] args) {
- // drop the 'this' and make the call
- return CallWithContext(context, func, args);
- }
-
- public static object ToPythonType(PythonType dt) {
- if (dt != null) {
- return ((object)dt.OldClass) ?? ((object)dt);
- }
- return null;
- }
-
- public static object CallWithArgsTupleAndContext(CodeContext/*!*/ context, object func, object[] args, object argsTuple) {
- PythonTuple tp = argsTuple as PythonTuple;
- if (tp != null) {
- object[] nargs = new object[args.Length + tp.__len__()];
- for (int i = 0; i < args.Length; i++) nargs[i] = args[i];
- for (int i = 0; i < tp.__len__(); i++) nargs[i + args.Length] = tp[i];
- return CallWithContext(context, func, nargs);
- }
-
- List allArgs = PythonOps.MakeEmptyList(args.Length + 10);
- allArgs.AddRange(args);
- IEnumerator e = PythonOps.GetEnumerator(argsTuple);
- while (e.MoveNext()) allArgs.AddNoLock(e.Current);
-
- return CallWithContext(context, func, allArgs.GetObjectArray());
- }
-
- [Obsolete("Use ObjectOpertaions instead")]
- public static object CallWithArgsTupleAndKeywordDictAndContext(CodeContext/*!*/ context, object func, object[] args, string[] names, object argsTuple, object kwDict) {
- IDictionary kws = kwDict as IDictionary;
- if (kws == null && kwDict != null) throw PythonOps.TypeError("argument after ** must be a dictionary");
-
- if ((kws == null || kws.Count == 0) && names.Length == 0) {
- List<object> largs = new List<object>(args);
- if (argsTuple != null) {
- foreach (object arg in PythonOps.GetCollection(argsTuple))
- largs.Add(arg);
- }
- return CallWithContext(context, func, largs.ToArray());
- } else {
- List<object> largs;
-
- if (argsTuple != null && args.Length == names.Length) {
- PythonTuple tuple = argsTuple as PythonTuple;
- if (tuple == null) tuple = new PythonTuple(argsTuple);
-
- largs = new List<object>(tuple);
- largs.AddRange(args);
- } else {
- largs = new List<object>(args);
- if (argsTuple != null) {
- largs.InsertRange(args.Length - names.Length, PythonTuple.Make(argsTuple));
- }
- }
-
- List<string> lnames = new List<string>(names);
-
- if (kws != null) {
- IDictionaryEnumerator ide = kws.GetEnumerator();
- while (ide.MoveNext()) {
- lnames.Add((string)ide.Key);
- largs.Add(ide.Value);
- }
- }
-
- return PythonCalls.CallWithKeywordArgs(context, func, largs.ToArray(), lnames.ToArray());
- }
- }
-
- public static object CallWithKeywordArgs(CodeContext/*!*/ context, object func, object[] args, string[] names) {
- return PythonCalls.CallWithKeywordArgs(context, func, args, names);
- }
-
- public static object CallWithArgsTuple(object func, object[] args, object argsTuple) {
- PythonTuple tp = argsTuple as PythonTuple;
- if (tp != null) {
- object[] nargs = new object[args.Length + tp.__len__()];
- for (int i = 0; i < args.Length; i++) nargs[i] = args[i];
- for (int i = 0; i < tp.__len__(); i++) nargs[i + args.Length] = tp[i];
- return PythonCalls.Call(func, nargs);
- }
-
- List allArgs = PythonOps.MakeEmptyList(args.Length + 10);
- allArgs.AddRange(args);
- IEnumerator e = PythonOps.GetEnumerator(argsTuple);
- while (e.MoveNext()) allArgs.AddNoLock(e.Current);
-
- return PythonCalls.Call(func, allArgs.GetObjectArray());
- }
-
- public static object GetIndex(CodeContext/*!*/ context, object o, object index) {
- PythonContext pc = PythonContext.GetContext(context);
- return pc.GetIndexSite.Target(pc.GetIndexSite, o, index);
- }
-
- public static bool TryGetBoundAttr(object o, string name, out object ret) {
- return TryGetBoundAttr(DefaultContext.Default, o, name, out ret);
- }
-
- public static void SetAttr(CodeContext/*!*/ context, object o, string name, object value) {
- PythonContext.GetContext(context).SetAttr(context, o, name, value);
- }
-
- public static bool TryGetBoundAttr(CodeContext/*!*/ context, object o, string name, out object ret) {
- return DynamicHelpers.GetPythonType(o).TryGetBoundAttr(context, o, name, out ret);
- }
-
- public static void DeleteAttr(CodeContext/*!*/ context, object o, string name) {
- PythonContext.GetContext(context).DeleteAttr(context, o, name);
- }
-
- public static bool HasAttr(CodeContext/*!*/ context, object o, string name) {
- object dummy;
- try {
- return TryGetBoundAttr(context, o, name, out dummy);
- } catch (SystemExitException) {
- throw;
- } catch (KeyboardInterruptException) {
- // we don't catch ThreadAbortException because it will
- // automatically re-throw on it's own.
- throw;
- } catch {
- return false;
- }
- }
-
- public static object GetBoundAttr(CodeContext/*!*/ context, object o, string name) {
- object ret;
- if (!DynamicHelpers.GetPythonType(o).TryGetBoundAttr(context, o, name, out ret)) {
- if (o is OldClass) {
- throw PythonOps.AttributeError("type object '{0}' has no attribute '{1}'",
- ((OldClass)o).Name, name);
- } else {
- throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'", PythonTypeOps.GetName(o), name);
- }
- }
-
- return ret;
- }
-
- public static void ObjectSetAttribute(CodeContext/*!*/ context, object o, string name, object value) {
- if (!DynamicHelpers.GetPythonType(o).TrySetNonCustomMember(context, o, name, value))
- throw AttributeErrorForMissingOrReadonly(context, DynamicHelpers.GetPythonType(o), name);
- }
-
- public static void ObjectDeleteAttribute(CodeContext/*!*/ context, object o, string name) {
- if (!DynamicHelpers.GetPythonType(o).TryDeleteNonCustomMember(context, o, name)) {
- throw AttributeErrorForMissingOrReadonly(context, DynamicHelpers.GetPythonType(o), name);
- }
- }
-
- public static object ObjectGetAttribute(CodeContext/*!*/ context, object o, string name) {
- OldClass oc = o as OldClass;
- if (oc != null) {
- return oc.GetMember(context, name);
- }
-
- object value;
- if (DynamicHelpers.GetPythonType(o).TryGetNonCustomMember(context, o, name, out value)) {
- return value;
- }
-
- throw PythonOps.AttributeErrorForObjectMissingAttribute(o, name);
- }
-
- internal static IList<string> GetStringMemberList(IPythonMembersList pyMemList) {
- List<string> res = new List<string>();
- foreach (object o in pyMemList.GetMemberNames(DefaultContext.Default)) {
- if (o is string) {
- res.Add((string)o);
- }
- }
- return res;
- }
-
- public static IList<object> GetAttrNames(CodeContext/*!*/ context, object o) {
- IPythonMembersList pyMemList = o as IPythonMembersList;
- if (pyMemList != null) {
- return pyMemList.GetMemberNames(context);
- }
-
- IMembersList memList = o as IMembersList;
- if (memList != null) {
- return new List(memList.GetMemberNames());
- }
-
- IPythonObject po = o as IPythonObject;
- if (po != null) {
- return po.PythonType.GetMemberNames(context, o);
- }
-
- List res = DynamicHelpers.GetPythonType(o).GetMemberNames(context, o);
-
- #if !SILVERLIGHT
-
- if (o != null && Microsoft.Scripting.ComInterop.ComBinder.IsComObject(o)) {
- foreach (string name in Microsoft.Scripting.ComInterop.ComBinder.GetDynamicMemberNames(o)) {
- if (!res.Contains(name)) {
- res.AddNoLock(name);
- }
- }
- }
- #endif
- return res;
- }
-
- /// <summary>
- /// Called from generated code emitted by NewTypeMaker.
- /// </summary>
- public static void CheckInitializedAttribute(object o, object self, string name) {
- if (o == Uninitialized.Instance) {
- throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'",
- PythonTypeOps.GetName(self),
- name);
- }
- }
-
- public static object GetUserSlotValue(CodeContext context, PythonTypeUserDescriptorSlot slot, object instance, PythonType type) {
- return slot.GetValue(context, instance, type);
- }
-
- /// <summary>
- /// Handles the descriptor protocol for user-defined objects that may implement __get__
- /// </summary>
- public static object GetUserDescriptor(object o, object instance, object context) {
- if (o is IPythonObject) {
- // slow, but only encountred for user defined descriptors.
- PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__get__");
- object ret;
- if (PythonContext.TryInvokeTernaryOperator(DefaultContext.Default,
- TernaryOperators.GetDescriptor,
- o,
- instance,
- context,
- out ret)) {
- return ret;
- }
- }
-
- return o;
- }
-
- /// <summary>
- /// Handles the descriptor protocol for user-defined objects that may implement __set__
- /// </summary>
- public static bool TrySetUserDescriptor(object o, object instance, object value) {
- if (o != null && o.GetType() == typeof(OldInstance)) return false; // only new-style classes have descriptors
-
- // slow, but only encountred for user defined descriptors.
- PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__set__");
-
- object dummy;
- return PythonContext.TryInvokeTernaryOperator(DefaultContext.Default,
- TernaryOperators.SetDescriptor,
- o,
- instance,
- value,
- out dummy);
- }
-
- /// <summary>
- /// Handles the descriptor protocol for user-defined objects that may implement __delete__
- /// </summary>
- public static bool TryDeleteUserDescriptor(object o, object instance) {
- if (o != null && o.GetType() == typeof(OldInstance)) return false; // only new-style classes can have descriptors
-
- // slow, but only encountred for user defined descriptors.
- PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__delete__");
-
- object dummy;
- return PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default,
- o,
- instance,
- "__delete__",
- out dummy);
- }
-
- public static object Invoke(CodeContext/*!*/ context, object target, string name, params object[] args) {
- return PythonCalls.Call(context, PythonOps.GetBoundAttr(context, target, name), args);
- }
-
- public static Delegate CreateDynamicDelegate(DynamicMethod meth, Type delegateType, object target) {
- // Always close delegate around its own instance of the frame
- return meth.CreateDelegate(delegateType, target);
- }
-
- public static double CheckMath(double v) {
- if (double.IsInfi