X Tutup
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using Microsoft.Scripting; using Microsoft.Scripting.Generation; using Microsoft.Scripting.Runtime; using IronPython.Runtime; using IronPython.Runtime.Binding; using IronPython.Runtime.Operations; using IronPython.Runtime.Types; [assembly: PythonModule("_operator", typeof(IronPython.Modules.PythonOperator))] namespace IronPython.Modules { public static class PythonOperator { public const string __doc__ = "Provides programmatic access to various operators (addition, accessing members, etc...)"; public class attrgetter { private readonly object[] _names; public attrgetter(params object[] attrs) { if (attrs == null || !attrs.All(x => x is string)) throw PythonOps.TypeError("attribute name must be a string"); if (attrs.Length == 0) throw PythonOps.TypeError("attrgetter expected 1 arguments, got 0"); this._names = attrs; } [SpecialName] public object Call(CodeContext context, object param) { if (_names.Length == 1) { return GetOneAttr(context, param, _names[0]); } object[] res = new object[_names.Length]; for (int i = 0; i < _names.Length; i++) { res[i] = GetOneAttr(context, param, _names[i]); } return PythonTuple.MakeTuple(res); } private static object GetOneAttr(CodeContext context, object param, object val) { string s = val as string; if (s == null) { throw PythonOps.TypeError("attribute name must be string"); } int dotPos = s.IndexOf('.'); if (dotPos >= 0) { object nextParam = GetOneAttr(context, param, s.Substring(0, dotPos)); return GetOneAttr(context, nextParam, s.Substring(dotPos + 1, s.Length - dotPos - 1)); } return PythonOps.GetBoundAttr(context, param, s); } } public class itemgetter { private readonly object[] _items; public itemgetter([NotNull]params object[] items) { if (items.Length == 0) { throw PythonOps.TypeError("itemgetter needs at least one argument"); } _items = items; } [SpecialName] public object Call(CodeContext/*!*/ context, object param) { if (_items.Length == 1) { return PythonOps.GetIndex(context, param, _items[0]); } object[] res = new object[_items.Length]; for (int i = 0; i < _items.Length; i++) { res[i] = PythonOps.GetIndex(context, param, _items[i]); } return PythonTuple.MakeTuple(res); } } [PythonType] public class methodcaller { private readonly string _name; private readonly object[] _args; private readonly IDictionary _dict; public methodcaller(params object[] args) { if (args == null) throw PythonOps.TypeError("TypeError: method name must be a string"); if (args.Length == 0) throw PythonOps.TypeError("methodcaller needs at least one argument, the method name"); _name = args[0] as string; if (_name == null) throw PythonOps.TypeError("TypeError: method name must be a string"); _args = args.Skip(1).ToArray(); } public methodcaller([ParamDictionary]IDictionary kwargs, params object[] args) : this(args) { _dict = kwargs; } public override string ToString() { return String.Format("", _name); } [SpecialName] public object Call(CodeContext/*!*/ context, object param) { object method = PythonOps.GetBoundAttr(context, param, _name); if (_dict == null) { return PythonOps.CallWithContext(context, method, _args); } else { return PythonCalls.CallWithKeywordArgs(context, method, _args, _dict); } } } public static object lt(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.LessThan, a, b); } public static object le(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.LessThanOrEqual, a, b); } public static object eq(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Equal, a, b); } public static object ne(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.NotEqual, a, b); } public static object ge(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.GreaterThanOrEqual, a, b); } public static object gt(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.GreaterThan, a, b); } public static bool not_(object o) { return PythonOps.Not(o); } public static bool truth(object o) { return PythonOps.IsTrue(o); } public static object is_(object a, object b) { return PythonOps.Is(a, b); } public static object is_not(object a, object b) { return PythonOps.IsNot(a, b); } public static object abs(CodeContext context, object o) { return Builtin.abs(context, o); } public static object add(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Add, a, b); } public static object and_(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.BitwiseAnd, a, b); } public static object floordiv(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.FloorDivide, a, b); } public static object inv(CodeContext/*!*/ context, object o) { return PythonOps.OnesComplement(o); } public static object invert(CodeContext/*!*/ context, object o) { return PythonOps.OnesComplement(o); } public static object lshift(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.LeftShift, a, b); } public static object mod(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Mod, a, b); } public static object mul(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Multiply, a, b); } public static object neg(object o) { return PythonOps.Negate(o); } public static object or_(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.BitwiseOr, a, b); } public static object pos(object o) { return PythonOps.Plus(o); } public static object pow(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Power, a, b); } public static object rshift(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.RightShift, a, b); } public static object sub(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.Subtract, a, b); } public static object truediv(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.TrueDivide, a, b); } public static object xor(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.ExclusiveOr, a, b); } public static object concat(CodeContext/*!*/ context, object a, object b) { TestBothSequence(a, b); return context.LanguageContext.Operation(PythonOperationKind.Add, a, b); } public static bool contains(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Contains(b, a); } public static int countOf(CodeContext/*!*/ context, object a, object b) { System.Collections.IEnumerator e = PythonOps.GetEnumerator(a); int count = 0; while (e.MoveNext()) { if (PythonOps.IsOrEqualsRetBool(context, e.Current, b)) { count++; } } return count; } public static void delitem(CodeContext/*!*/ context, object a, object b) { context.LanguageContext.DelIndex(a, b); } public static object getitem(CodeContext/*!*/ context, object a, object b) { return PythonOps.GetIndex(context, a, b); } public static int indexOf(CodeContext/*!*/ context, object a, object b) { System.Collections.IEnumerator e = PythonOps.GetEnumerator(a); int index = 0; while (e.MoveNext()) { if (PythonOps.IsOrEqualsRetBool(context, e.Current, b)) { return index; } index++; } throw PythonOps.ValueError("object not in sequence"); } public static void setitem(CodeContext/*!*/ context, object a, object b, object c) { context.LanguageContext.SetIndex(a, b, c); } private static bool isSequenceType(object o) { return CompilerHelpers.GetType(o) != typeof(PythonType) && !(o is PythonDictionary) && ( o is System.Collections.ICollection || o is System.Collections.IEnumerable || o is System.Collections.IEnumerator || o is System.Collections.IList || PythonOps.HasAttr(DefaultContext.Default, o, "__getitem__")); } public static object iadd(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceAdd, a, b); } public static object iand(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceBitwiseAnd, a, b); } public static object ifloordiv(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceFloorDivide, a, b); } public static object ilshift(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceLeftShift, a, b); } public static object imod(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceMod, a, b); } public static object imul(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceMultiply, a, b); } public static object ior(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceBitwiseOr, a, b); } public static object ipow(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlacePower, a, b); } public static object irshift(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceRightShift, a, b); } public static object isub(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceSubtract, a, b); } public static object itruediv(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceTrueDivide, a, b); } public static object ixor(CodeContext/*!*/ context, object a, object b) { return context.LanguageContext.Operation(PythonOperationKind.InPlaceExclusiveOr, a, b); } public static object iconcat(CodeContext/*!*/ context, object a, object b) { TestBothSequence(a, b); return context.LanguageContext.Operation(PythonOperationKind.InPlaceAdd, a, b); } public static object index(object a) { return Converter.ConvertToIndex(a); } [Documentation(@"compare_digest(a, b)-> bool Return 'a == b'. This function uses an approach designed to prevent timing analysis, making it appropriate for cryptography. a and b must both be of the same type: either str (ASCII only), or any type that supports the buffer protocol (e.g. bytes). Note: If a and b are of different lengths, or if an error occurs, a timing attack could theoretically reveal information about the types and lengths of a and b--but not their values.")] public static bool _compare_digest(object a, object b) { if(a is string && b is string) { string aStr = a as string; string bStr = b as string; return CompareBytes(aStr.MakeByteArray(), bStr.MakeByteArray()); } else if(a is IBufferProtocol && b is IBufferProtocol) { IBufferProtocol aBuf = a as IBufferProtocol; IBufferProtocol bBuf = b as IBufferProtocol; if(aBuf.NumberDimensions > 1 || bBuf.NumberDimensions > 1) { throw PythonOps.BufferError("Buffer must be single dimension"); } return CompareBytes(aBuf.ToBytes(0, null), bBuf.ToBytes(0, null)); } throw PythonOps.TypeError("unsupported operand types(s) or combination of types: '{0}' and '{1}", PythonOps.GetPythonTypeName(a), PythonOps.GetPythonTypeName(b)); } private static bool CompareBytes(IEnumerable a, IEnumerable b) { var aList = a.ToList(); var bList = b.ToList(); int len_b = bList.Count, len_a = aList.Count, length = len_b, result = 0; List left = null, right = bList; if(len_a == length) { left = aList; result = 0; } if(len_a != length) { left = bList; result = 1; } for(int i = 0; i < length; i++) { result |= (left[i] ^ right[i]); } return result == 0; } private static void TestBothSequence(object a, object b) { if (!isSequenceType(a)) { throw PythonOps.TypeError("'{0}' object cannot be concatenated", PythonTypeOps.GetName(a)); } else if (!isSequenceType(b)) { throw PythonOps.TypeError("cannot concatenate '{0}' and '{1} objects", PythonTypeOps.GetName(a), PythonTypeOps.GetName(b)); } } } }
X Tutup