PageRenderTime 53ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/DLR_Main/Languages/IronPython/IronPython/Runtime/Operations/PythonOps.cs

https://bitbucket.org/mdavid/dlr
C# | 1196 lines | 883 code | 208 blank | 105 comment | 332 complexity | feb72380f521425e952eaa41adc94b22 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. using System.Linq.Expressions;
  17. using System.Numerics;
  18. using Microsoft.Scripting.Ast;
  19. #else
  20. using Microsoft.Scripting.Ast;
  21. using Microsoft.Scripting.Math;
  22. using Complex = Microsoft.Scripting.Math.Complex64;
  23. #endif
  24. using System;
  25. using System.Collections;
  26. using System.Collections.Generic;
  27. using System.Diagnostics;
  28. using System.Dynamic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Reflection.Emit;
  32. using System.Runtime.CompilerServices;
  33. using System.Runtime.InteropServices;
  34. using System.Text;
  35. using System.Threading;
  36. using Microsoft.Scripting;
  37. using Microsoft.Scripting.Actions;
  38. using Microsoft.Scripting.Generation;
  39. using Microsoft.Scripting.Hosting.Providers;
  40. using Microsoft.Scripting.Hosting.Shell;
  41. using Microsoft.Scripting.Runtime;
  42. using Microsoft.Scripting.Utils;
  43. using IronPython.Compiler;
  44. using IronPython.Hosting;
  45. using IronPython.Modules;
  46. using IronPython.Runtime.Binding;
  47. using IronPython.Runtime.Exceptions;
  48. using IronPython.Runtime.Types;
  49. #if !SILVERLIGHT
  50. using System.ComponentModel;
  51. #endif
  52. namespace IronPython.Runtime.Operations {
  53. /// <summary>
  54. /// Contains functions that are called directly from
  55. /// generated code to perform low-level runtime functionality.
  56. /// </summary>
  57. public static partial class PythonOps {
  58. #region Shared static data
  59. [ThreadStatic]
  60. private static List<object> InfiniteRepr;
  61. // The "current" exception on this thread that will be returned via sys.exc_info()
  62. [ThreadStatic]
  63. internal static Exception RawException;
  64. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  65. public static readonly PythonTuple EmptyTuple = PythonTuple.EMPTY;
  66. private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
  67. #endregion
  68. public static BigInteger MakeIntegerFromHex(string s) {
  69. return LiteralParser.ParseBigInteger(s, 16);
  70. }
  71. public static PythonDictionary MakeDict(int size) {
  72. return new PythonDictionary(size);
  73. }
  74. public static PythonDictionary MakeEmptyDict() {
  75. return new PythonDictionary(EmptyDictionaryStorage.Instance);
  76. }
  77. /// <summary>
  78. /// Creates a new dictionary extracting the keys and values from the
  79. /// provided data array. Keys/values are adjacent in the array with
  80. /// the value coming first.
  81. /// </summary>
  82. public static PythonDictionary MakeDictFromItems(params object[] data) {
  83. return new PythonDictionary(new CommonDictionaryStorage(data, false));
  84. }
  85. public static PythonDictionary MakeConstantDict(object items) {
  86. return new PythonDictionary((ConstantDictionaryStorage)items);
  87. }
  88. public static object MakeConstantDictStorage(params object[] data) {
  89. return new ConstantDictionaryStorage(new CommonDictionaryStorage(data, false));
  90. }
  91. public static SetCollection MakeSet(params object[] items) {
  92. return new SetCollection(items);
  93. }
  94. public static SetCollection MakeEmptySet() {
  95. return new SetCollection();
  96. }
  97. /// <summary>
  98. /// Creates a new dictionary extracting the keys and values from the
  99. /// provided data array. Keys/values are adjacent in the array with
  100. /// the value coming first.
  101. /// </summary>
  102. public static PythonDictionary MakeHomogeneousDictFromItems(object[] data) {
  103. return new PythonDictionary(new CommonDictionaryStorage(data, true));
  104. }
  105. public static bool IsCallable(CodeContext/*!*/ context, object o) {
  106. // This tells if an object can be called, but does not make a claim about the parameter list.
  107. // In 1.x, we could check for certain interfaces like ICallable*, but those interfaces were deprecated
  108. // in favor of dynamic sites.
  109. // This is difficult to infer because we'd need to simulate the entire callbinder, which can include
  110. // looking for [SpecialName] call methods and checking for a rule from IDynamicMetaObjectProvider. But even that wouldn't
  111. // be complete since sites require the argument list of the call, and we only have the instance here.
  112. // Thus check a dedicated IsCallable operator. This lets each object describe if it's callable.
  113. // Invoke Operator.IsCallable on the object.
  114. return PythonContext.GetContext(context).IsCallable(o);
  115. }
  116. public static bool IsTrue(object o) {
  117. return Converter.ConvertToBoolean(o);
  118. }
  119. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
  120. public static List<object> GetReprInfinite() {
  121. if (InfiniteRepr == null) {
  122. InfiniteRepr = new List<object>();
  123. }
  124. return InfiniteRepr;
  125. }
  126. [LightThrowing]
  127. internal static object LookupEncodingError(CodeContext/*!*/ context, string name) {
  128. Dictionary<string, object> errorHandlers = PythonContext.GetContext(context).ErrorHandlers;
  129. lock (errorHandlers) {
  130. if (errorHandlers.ContainsKey(name))
  131. return errorHandlers[name];
  132. else
  133. return LightExceptions.Throw(PythonOps.LookupError("unknown error handler name '{0}'", name));
  134. }
  135. }
  136. internal static void RegisterEncodingError(CodeContext/*!*/ context, string name, object handler) {
  137. Dictionary<string, object> errorHandlers = PythonContext.GetContext(context).ErrorHandlers;
  138. lock (errorHandlers) {
  139. if (!PythonOps.IsCallable(context, handler))
  140. throw PythonOps.TypeError("handler must be callable");
  141. errorHandlers[name] = handler;
  142. }
  143. }
  144. internal static PythonTuple LookupEncoding(CodeContext/*!*/ context, string encoding) {
  145. PythonContext.GetContext(context).EnsureEncodings();
  146. List<object> searchFunctions = PythonContext.GetContext(context).SearchFunctions;
  147. string normalized = encoding.ToLower().Replace(' ', '-');
  148. if (normalized.IndexOf(Char.MinValue) != -1) {
  149. throw PythonOps.TypeError("lookup string cannot contain null character");
  150. }
  151. lock (searchFunctions) {
  152. for (int i = 0; i < searchFunctions.Count; i++) {
  153. object res = PythonCalls.Call(context, searchFunctions[i], normalized);
  154. if (res != null) return (PythonTuple)res;
  155. }
  156. }
  157. throw PythonOps.LookupError("unknown encoding: {0}", encoding);
  158. }
  159. internal static void RegisterEncoding(CodeContext/*!*/ context, object search_function) {
  160. if (!PythonOps.IsCallable(context, search_function))
  161. throw PythonOps.TypeError("search_function must be callable");
  162. List<object> searchFunctions = PythonContext.GetContext(context).SearchFunctions;
  163. lock (searchFunctions) {
  164. searchFunctions.Add(search_function);
  165. }
  166. }
  167. internal static string GetPythonTypeName(object obj) {
  168. OldInstance oi = obj as OldInstance;
  169. if (oi != null) return oi._class._name.ToString();
  170. else return PythonTypeOps.GetName(obj);
  171. }
  172. public static string Repr(CodeContext/*!*/ context, object o) {
  173. if (o == null) return "None";
  174. string s;
  175. if ((s = o as string) != null) return StringOps.__repr__(s);
  176. if (o is int) return Int32Ops.__repr__((int)o);
  177. if (o is long) return ((long)o).ToString() + "L";
  178. // could be a container object, we need to detect recursion, but only
  179. // for our own built-in types that we're aware of. The user can setup
  180. // infinite recursion in their own class if they want.
  181. ICodeFormattable f = o as ICodeFormattable;
  182. if (f != null) {
  183. return f.__repr__(context);
  184. }
  185. PerfTrack.NoteEvent(PerfTrack.Categories.Temporary, "Repr " + o.GetType().FullName);
  186. return PythonContext.InvokeUnaryOperator(context, UnaryOperators.Repr, o) as string;
  187. }
  188. public static List<object> GetAndCheckInfinite(object o) {
  189. List<object> infinite = GetReprInfinite();
  190. foreach (object o2 in infinite) {
  191. if (o == o2) {
  192. return null;
  193. }
  194. }
  195. return infinite;
  196. }
  197. public static string ToString(object o) {
  198. return ToString(DefaultContext.Default, o);
  199. }
  200. public static string ToString(CodeContext/*!*/ context, object o) {
  201. string x = o as string;
  202. PythonType dt;
  203. OldClass oc;
  204. if (x != null) return x;
  205. if (o == null) return "None";
  206. if (o is double) return DoubleOps.__str__(context, (double)o);
  207. if ((dt = o as PythonType) != null) return dt.__repr__(DefaultContext.Default);
  208. if ((oc = o as OldClass) != null) return oc.ToString();
  209. object value = PythonContext.InvokeUnaryOperator(context, UnaryOperators.String, o);
  210. string ret = value as string;
  211. if (ret == null) {
  212. Extensible<string> es = value as Extensible<string>;
  213. if (es == null) {
  214. throw PythonOps.TypeError("expected str, got {0} from __str__", PythonTypeOps.GetName(value));
  215. }
  216. ret = es.Value;
  217. }
  218. return ret;
  219. }
  220. public static string FormatString(CodeContext context, string str, object data) {
  221. return new StringFormatter(context, str, data).Format();
  222. }
  223. public static string FormatUnicode(CodeContext context, string str, object data) {
  224. return new StringFormatter(context, str, data, true).Format();
  225. }
  226. public static object Plus(object o) {
  227. object ret;
  228. if (o is int) return o;
  229. else if (o is double) return o;
  230. else if (o is BigInteger) return o;
  231. else if (o is Complex) return o;
  232. else if (o is long) return o;
  233. else if (o is float) return o;
  234. else if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? 1 : 0);
  235. if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__pos__", out ret) &&
  236. ret != NotImplementedType.Value) {
  237. return ret;
  238. }
  239. throw PythonOps.TypeError("bad operand type for unary +");
  240. }
  241. public static object Negate(object o) {
  242. if (o is int) return Int32Ops.Negate((int)o);
  243. else if (o is double) return DoubleOps.Negate((double)o);
  244. else if (o is long) return Int64Ops.Negate((long)o);
  245. else if (o is BigInteger) return BigIntegerOps.Negate((BigInteger)o);
  246. else if (o is Complex) return -(Complex)o;
  247. else if (o is float) return DoubleOps.Negate((float)o);
  248. else if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? -1 : 0);
  249. object ret;
  250. if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__neg__", out ret) &&
  251. ret != NotImplementedType.Value) {
  252. return ret;
  253. }
  254. throw PythonOps.TypeError("bad operand type for unary -");
  255. }
  256. public static bool IsSubClass(PythonType/*!*/ c, PythonType/*!*/ typeinfo) {
  257. Assert.NotNull(c, typeinfo);
  258. if (c.OldClass != null) {
  259. return typeinfo.__subclasscheck__(c.OldClass);
  260. }
  261. return typeinfo.__subclasscheck__(c);
  262. }
  263. public static bool IsSubClass(CodeContext context, PythonType c, object typeinfo) {
  264. if (c == null) throw PythonOps.TypeError("issubclass: arg 1 must be a class");
  265. if (typeinfo == null) throw PythonOps.TypeError("issubclass: arg 2 must be a class");
  266. PythonTuple pt = typeinfo as PythonTuple;
  267. PythonContext pyContext = PythonContext.GetContext(context);
  268. if (pt != null) {
  269. // Recursively inspect nested tuple(s)
  270. foreach (object o in pt) {
  271. try {
  272. FunctionPushFrame(pyContext);
  273. if (IsSubClass(context, c, o)) {
  274. return true;
  275. }
  276. } finally {
  277. FunctionPopFrame();
  278. }
  279. }
  280. return false;
  281. }
  282. OldClass oc = typeinfo as OldClass;
  283. if (oc != null) {
  284. return c.IsSubclassOf(oc.TypeObject);
  285. }
  286. Type t = typeinfo as Type;
  287. if (t != null) {
  288. typeinfo = DynamicHelpers.GetPythonTypeFromType(t);
  289. }
  290. object bases;
  291. PythonType dt = typeinfo as PythonType;
  292. if (dt == null) {
  293. if (!PythonOps.TryGetBoundAttr(typeinfo, "__bases__", out bases)) {
  294. //!!! deal with classes w/ just __bases__ defined.
  295. throw PythonOps.TypeErrorForBadInstance("issubclass(): {0} is not a class nor a tuple of classes", typeinfo);
  296. }
  297. IEnumerator ie = PythonOps.GetEnumerator(bases);
  298. while (ie.MoveNext()) {
  299. PythonType baseType = ie.Current as PythonType;
  300. if (baseType == null) {
  301. OldClass ocType = ie.Current as OldClass;
  302. if (ocType == null) {
  303. continue;
  304. }
  305. baseType = ocType.TypeObject;
  306. }
  307. if (c.IsSubclassOf(baseType)) return true;
  308. }
  309. return false;
  310. }
  311. return IsSubClass(c, dt);
  312. }
  313. public static bool IsInstance(object o, PythonType typeinfo) {
  314. if (typeinfo.__instancecheck__(o)) {
  315. return true;
  316. }
  317. return IsInstanceDynamic(o, typeinfo, DynamicHelpers.GetPythonType(o));
  318. }
  319. public static bool IsInstance(CodeContext context, object o, PythonTuple typeinfo) {
  320. PythonContext pyContext = PythonContext.GetContext(context);
  321. foreach (object type in typeinfo) {
  322. try {
  323. PythonOps.FunctionPushFrame(pyContext);
  324. if (type is PythonType) {
  325. if (IsInstance(o, (PythonType)type)) {
  326. return true;
  327. }
  328. } else if (type is PythonTuple) {
  329. if (IsInstance(context, o, (PythonTuple)type)) {
  330. return true;
  331. }
  332. } else if (IsInstance(context, o, type)) {
  333. return true;
  334. }
  335. } finally {
  336. PythonOps.FunctionPopFrame();
  337. }
  338. }
  339. return false;
  340. }
  341. public static bool IsInstance(CodeContext context, object o, object typeinfo) {
  342. if (typeinfo == null) throw PythonOps.TypeError("isinstance: arg 2 must be a class, type, or tuple of classes and types");
  343. PythonTuple tt = typeinfo as PythonTuple;
  344. if (tt != null) {
  345. return IsInstance(context, o, tt);
  346. }
  347. if (typeinfo is OldClass) {
  348. // old instances are strange - they all share a common type
  349. // of instance but they can "be subclasses" of other
  350. // OldClass's. To check their types we need the actual
  351. // instance.
  352. OldInstance oi = o as OldInstance;
  353. if (oi != null) return oi._class.IsSubclassOf(typeinfo);
  354. }
  355. PythonType odt = DynamicHelpers.GetPythonType(o);
  356. if (IsSubClass(context, odt, typeinfo)) {
  357. return true;
  358. }
  359. return IsInstanceDynamic(o, typeinfo);
  360. }
  361. private static bool IsInstanceDynamic(object o, object typeinfo) {
  362. return IsInstanceDynamic(o, typeinfo, DynamicHelpers.GetPythonType(o));
  363. }
  364. private static bool IsInstanceDynamic(object o, object typeinfo, PythonType odt) {
  365. if (o is IPythonObject || o is OldInstance) {
  366. object cls;
  367. if (PythonOps.TryGetBoundAttr(o, "__class__", out cls) &&
  368. (!object.ReferenceEquals(odt, cls))) {
  369. return IsSubclassSlow(cls, typeinfo);
  370. }
  371. }
  372. return false;
  373. }
  374. private static bool IsSubclassSlow(object cls, object typeinfo) {
  375. Debug.Assert(typeinfo != null);
  376. if (cls == null) return false;
  377. // Same type
  378. if (cls.Equals(typeinfo)) {
  379. return true;
  380. }
  381. // Get bases
  382. object bases;
  383. if (!PythonOps.TryGetBoundAttr(cls, "__bases__", out bases)) {
  384. return false; // no bases, cannot be subclass
  385. }
  386. PythonTuple tbases = bases as PythonTuple;
  387. if (tbases == null) {
  388. return false; // not a tuple, cannot be subclass
  389. }
  390. foreach (object baseclass in tbases) {
  391. if (IsSubclassSlow(baseclass, typeinfo)) return true;
  392. }
  393. return false;
  394. }
  395. public static object OnesComplement(object o) {
  396. if (o is int) return ~(int)o;
  397. if (o is long) return ~(long)o;
  398. if (o is BigInteger) return ~((BigInteger)o);
  399. if (o is bool) return ScriptingRuntimeHelpers.Int32ToObject((bool)o ? -2 : -1);
  400. object ret;
  401. if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default, o, "__invert__", out ret) &&
  402. ret != NotImplementedType.Value)
  403. return ret;
  404. throw PythonOps.TypeError("bad operand type for unary ~");
  405. }
  406. public static bool Not(object o) {
  407. return !IsTrue(o);
  408. }
  409. public static object Is(object x, object y) {
  410. return x == y ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  411. }
  412. public static bool IsRetBool(object x, object y) {
  413. return x == y;
  414. }
  415. public static object IsNot(object x, object y) {
  416. return x != y ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  417. }
  418. public static bool IsNotRetBool(object x, object y) {
  419. return x != y;
  420. }
  421. internal delegate T MultiplySequenceWorker<T>(T self, int count);
  422. /// <summary>
  423. /// Wraps up all the semantics of multiplying sequences so that all of our sequences
  424. /// don't duplicate the same logic. When multiplying sequences we need to deal with
  425. /// only multiplying by valid sequence types (ints, not floats), support coercion
  426. /// to integers if the type supports it, not multiplying by None, and getting the
  427. /// right semantics for multiplying by negative numbers and 1 (w/ and w/o subclasses).
  428. ///
  429. /// This function assumes that it is only called for case where count is not implicitly
  430. /// coercible to int so that check is skipped.
  431. /// </summary>
  432. internal static object MultiplySequence<T>(MultiplySequenceWorker<T> multiplier, T sequence, Index count, bool isForward) {
  433. if (isForward && count != null) {
  434. object ret;
  435. if (PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default, count.Value, sequence, "__rmul__", out ret)) {
  436. if (ret != NotImplementedType.Value) return ret;
  437. }
  438. }
  439. int icount = GetSequenceMultiplier(sequence, count.Value);
  440. if (icount < 0) icount = 0;
  441. return multiplier(sequence, icount);
  442. }
  443. internal static int GetSequenceMultiplier(object sequence, object count) {
  444. int icount;
  445. if (!Converter.TryConvertToIndex(count, out icount)) {
  446. PythonTuple pt = null;
  447. if (count is OldInstance || !DynamicHelpers.GetPythonType(count).IsSystemType) {
  448. pt = Builtin.TryCoerce(DefaultContext.Default, count, sequence) as PythonTuple;
  449. }
  450. if (pt == null || !Converter.TryConvertToIndex(pt[0], out icount)) {
  451. throw TypeError("can't multiply sequence by non-int of type '{0}'", PythonTypeOps.GetName(count));
  452. }
  453. }
  454. return icount;
  455. }
  456. public static object Equal(CodeContext/*!*/ context, object x, object y) {
  457. PythonContext pc = PythonContext.GetContext(context);
  458. return pc.EqualSite.Target(pc.EqualSite, x, y);
  459. }
  460. public static bool EqualRetBool(object x, object y) {
  461. //TODO just can't seem to shake these fast paths
  462. if (x is int && y is int) { return ((int)x) == ((int)y); }
  463. if (x is string && y is string) { return ((string)x).Equals((string)y); }
  464. return DynamicHelpers.GetPythonType(x).EqualRetBool(x, y);
  465. }
  466. public static bool EqualRetBool(CodeContext/*!*/ context, object x, object y) {
  467. // TODO: use context
  468. //TODO just can't seem to shake these fast paths
  469. if (x is int && y is int) { return ((int)x) == ((int)y); }
  470. if (x is string && y is string) { return ((string)x).Equals((string)y); }
  471. return DynamicHelpers.GetPythonType(x).EqualRetBool(x, y);
  472. }
  473. public static int Compare(object x, object y) {
  474. return Compare(DefaultContext.Default, x, y);
  475. }
  476. public static int Compare(CodeContext/*!*/ context, object x, object y) {
  477. if (x == y) return 0;
  478. return DynamicHelpers.GetPythonType(x).Compare(x, y);
  479. }
  480. public static object CompareEqual(int res) {
  481. return res == 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  482. }
  483. public static object CompareNotEqual(int res) {
  484. return res == 0 ? ScriptingRuntimeHelpers.False : ScriptingRuntimeHelpers.True;
  485. }
  486. public static object CompareGreaterThan(int res) {
  487. return res > 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  488. }
  489. public static object CompareGreaterThanOrEqual(int res) {
  490. return res >= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  491. }
  492. public static object CompareLessThan(int res) {
  493. return res < 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  494. }
  495. public static object CompareLessThanOrEqual(int res) {
  496. return res <= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  497. }
  498. public static bool CompareTypesEqual(CodeContext/*!*/ context, object x, object y) {
  499. if (x == null && y == null) return true;
  500. if (x == null) return false;
  501. if (y == null) return false;
  502. if (DynamicHelpers.GetPythonType(x) == DynamicHelpers.GetPythonType(y)) {
  503. // avoid going to the ID dispenser if we have the same types...
  504. return x == y;
  505. }
  506. return PythonOps.CompareTypesWorker(context, false, x, y) == 0;
  507. }
  508. public static bool CompareTypesNotEqual(CodeContext/*!*/ context, object x, object y) {
  509. return PythonOps.CompareTypesWorker(context, false, x, y) != 0;
  510. }
  511. public static bool CompareTypesGreaterThan(CodeContext/*!*/ context, object x, object y) {
  512. return PythonOps.CompareTypes(context, x, y) > 0;
  513. }
  514. public static bool CompareTypesLessThan(CodeContext/*!*/ context, object x, object y) {
  515. return PythonOps.CompareTypes(context, x, y) < 0;
  516. }
  517. public static bool CompareTypesGreaterThanOrEqual(CodeContext/*!*/ context, object x, object y) {
  518. return PythonOps.CompareTypes(context, x, y) >= 0;
  519. }
  520. public static bool CompareTypesLessThanOrEqual(CodeContext/*!*/ context, object x, object y) {
  521. return PythonOps.CompareTypes(context, x, y) <= 0;
  522. }
  523. public static int CompareTypesWorker(CodeContext/*!*/ context, bool shouldWarn, object x, object y) {
  524. if (x == null && y == null) return 0;
  525. if (x == null) return -1;
  526. if (y == null) return 1;
  527. string name1, name2;
  528. int diff;
  529. if (DynamicHelpers.GetPythonType(x) != DynamicHelpers.GetPythonType(y)) {
  530. if (shouldWarn && PythonContext.GetContext(context).PythonOptions.WarnPython30) {
  531. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "comparing unequal types not supported in 3.x");
  532. }
  533. if (x.GetType() == typeof(OldInstance)) {
  534. name1 = ((OldInstance)x)._class.Name;
  535. if (y.GetType() == typeof(OldInstance)) {
  536. name2 = ((OldInstance)y)._class.Name;
  537. } else {
  538. // old instances are always less than new-style classes
  539. return -1;
  540. }
  541. } else if (y.GetType() == typeof(OldInstance)) {
  542. // old instances are always less than new-style classes
  543. return 1;
  544. } else {
  545. name1 = PythonTypeOps.GetName(x);
  546. name2 = PythonTypeOps.GetName(y);
  547. }
  548. diff = String.CompareOrdinal(name1, name2);
  549. if (diff == 0) {
  550. // if the types are different but have the same name compare based upon their types.
  551. diff = (int)(IdDispenser.GetId(DynamicHelpers.GetPythonType(x)) - IdDispenser.GetId(DynamicHelpers.GetPythonType(y)));
  552. }
  553. } else {
  554. diff = (int)(IdDispenser.GetId(x) - IdDispenser.GetId(y));
  555. }
  556. if (diff < 0) return -1;
  557. if (diff == 0) return 0;
  558. return 1;
  559. }
  560. public static int CompareTypes(CodeContext/*!*/ context, object x, object y) {
  561. return CompareTypesWorker(context, true, x, y);
  562. }
  563. public static object GreaterThanHelper(CodeContext/*!*/ context, object self, object other) {
  564. return InternalCompare(context, PythonOperationKind.GreaterThan, self, other);
  565. }
  566. public static object LessThanHelper(CodeContext/*!*/ context, object self, object other) {
  567. return InternalCompare(context, PythonOperationKind.LessThan, self, other);
  568. }
  569. public static object GreaterThanOrEqualHelper(CodeContext/*!*/ context, object self, object other) {
  570. return InternalCompare(context, PythonOperationKind.GreaterThanOrEqual, self, other);
  571. }
  572. public static object LessThanOrEqualHelper(CodeContext/*!*/ context, object self, object other) {
  573. return InternalCompare(context, PythonOperationKind.LessThanOrEqual, self, other);
  574. }
  575. internal static object InternalCompare(CodeContext/*!*/ context, PythonOperationKind op, object self, object other) {
  576. object ret;
  577. if (PythonTypeOps.TryInvokeBinaryOperator(context, self, other, Symbols.OperatorToSymbol(op), out ret))
  578. return ret;
  579. return NotImplementedType.Value;
  580. }
  581. public static int CompareToZero(object value) {
  582. double val;
  583. if (Converter.TryConvertToDouble(value, out val)) {
  584. if (val > 0) return 1;
  585. if (val < 0) return -1;
  586. return 0;
  587. }
  588. throw PythonOps.TypeErrorForBadInstance("an integer is required (got {0})", value);
  589. }
  590. public static int CompareArrays(object[] data0, int size0, object[] data1, int size1) {
  591. int size = Math.Min(size0, size1);
  592. for (int i = 0; i < size; i++) {
  593. int c = PythonOps.Compare(data0[i], data1[i]);
  594. if (c != 0) return c;
  595. }
  596. if (size0 == size1) return 0;
  597. return size0 > size1 ? +1 : -1;
  598. }
  599. public static int CompareArrays(object[] data0, int size0, object[] data1, int size1, IComparer comparer) {
  600. int size = Math.Min(size0, size1);
  601. for (int i = 0; i < size; i++) {
  602. int c = comparer.Compare(data0[i], data1[i]);
  603. if (c != 0) return c;
  604. }
  605. if (size0 == size1) return 0;
  606. return size0 > size1 ? +1 : -1;
  607. }
  608. public static bool ArraysEqual(object[] data0, int size0, object[] data1, int size1) {
  609. if (size0 != size1) {
  610. return false;
  611. }
  612. for (int i = 0; i < size0; i++) {
  613. if (data0[i] != null) {
  614. if (!EqualRetBool(data0[i], data1[i])) {
  615. return false;
  616. }
  617. } else if (data1[i] != null) {
  618. return false;
  619. }
  620. }
  621. return true;
  622. }
  623. public static bool ArraysEqual(object[] data0, int size0, object[] data1, int size1, IEqualityComparer comparer) {
  624. if (size0 != size1) {
  625. return false;
  626. }
  627. for (int i = 0; i < size0; i++) {
  628. if (data0[i] != null) {
  629. if (!comparer.Equals(data0[i], data1[i])) {
  630. return false;
  631. }
  632. } else if (data1[i] != null) {
  633. return false;
  634. }
  635. }
  636. return true;
  637. }
  638. public static object PowerMod(CodeContext/*!*/ context, object x, object y, object z) {
  639. object ret;
  640. if (z == null) {
  641. return PythonContext.GetContext(context).Operation(PythonOperationKind.Power, x, y);
  642. }
  643. if (x is int && y is int && z is int) {
  644. ret = Int32Ops.Power((int)x, (int)y, (int)z);
  645. if (ret != NotImplementedType.Value) return ret;
  646. } else if (x is BigInteger) {
  647. ret = BigIntegerOps.Power((BigInteger)x, y, z);
  648. if (ret != NotImplementedType.Value) return ret;
  649. }
  650. if (x is Complex || y is Complex || z is Complex) {
  651. throw PythonOps.ValueError("complex modulo");
  652. }
  653. if (PythonTypeOps.TryInvokeTernaryOperator(context, x, y, z, "__pow__", out ret)) {
  654. if (ret != NotImplementedType.Value) {
  655. return ret;
  656. } else if (!IsNumericObject(y) || !IsNumericObject(z)) {
  657. // special error message in this case...
  658. throw TypeError("pow() 3rd argument not allowed unless all arguments are integers");
  659. }
  660. }
  661. throw PythonOps.TypeErrorForBinaryOp("power with modulus", x, y);
  662. }
  663. public static long Id(object o) {
  664. return IdDispenser.GetId(o);
  665. }
  666. public static string HexId(object o) {
  667. return string.Format("0x{0:X16}", Id(o));
  668. }
  669. // For hash operators, it's essential that:
  670. // Cmp(x,y)==0 implies hash(x) == hash(y)
  671. //
  672. // Equality is a language semantic determined by the Python's numerical Compare() ops
  673. // in IronPython.Runtime.Operations namespaces.
  674. // For example, the CLR compares float(1.0) and int32(1) as different, but Python
  675. // compares them as equal. So Hash(1.0f) and Hash(1) must be equal.
  676. //
  677. // Python allows an equality relationship between int, double, BigInteger, and complex.
  678. // So each of these hash functions must be aware of their possible equality relationships
  679. // and hash appropriately.
  680. //
  681. // Types which differ in hashing from .NET have __hash__ functions defined in their
  682. // ops classes which do the appropriate hashing.
  683. public static int Hash(CodeContext/*!*/ context, object o) {
  684. return PythonContext.Hash(o);
  685. }
  686. public static object Hex(object o) {
  687. if (o is int) return Int32Ops.__hex__((int)o);
  688. else if (o is BigInteger) return BigIntegerOps.__hex__((BigInteger)o);
  689. object hex;
  690. if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
  691. o,
  692. "__hex__",
  693. out hex)) {
  694. if (!(hex is string) && !(hex is ExtensibleString))
  695. throw PythonOps.TypeError("hex expected string type as return, got '{0}'", PythonTypeOps.GetName(hex));
  696. return hex;
  697. }
  698. throw TypeError("hex() argument cannot be converted to hex");
  699. }
  700. public static object Oct(object o) {
  701. if (o is int) {
  702. return Int32Ops.__oct__((int)o);
  703. } else if (o is BigInteger) {
  704. return BigIntegerOps.__oct__((BigInteger)o);
  705. }
  706. object octal;
  707. if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
  708. o,
  709. "__oct__",
  710. out octal)) {
  711. if (!(octal is string) && !(octal is ExtensibleString))
  712. throw PythonOps.TypeError("hex expected string type as return, got '{0}'", PythonTypeOps.GetName(octal));
  713. return octal;
  714. }
  715. throw TypeError("oct() argument cannot be converted to octal");
  716. }
  717. public static int Length(object o) {
  718. string s = o as string;
  719. if (s != null) {
  720. return s.Length;
  721. }
  722. object[] os = o as object[];
  723. if (os != null) {
  724. return os.Length;
  725. }
  726. object len = PythonContext.InvokeUnaryOperator(DefaultContext.Default, UnaryOperators.Length, o, "len() of unsized object");
  727. int res;
  728. if (len is int) {
  729. res = (int)len;
  730. } else {
  731. res = Converter.ConvertToInt32(len);
  732. }
  733. if (res < 0) {
  734. throw PythonOps.ValueError("__len__ should return >= 0, got {0}", res);
  735. }
  736. return res;
  737. }
  738. public static object CallWithContext(CodeContext/*!*/ context, object func, params object[] args) {
  739. return PythonCalls.Call(context, func, args);
  740. }
  741. /// <summary>
  742. /// Supports calling of functions that require an explicit 'this'
  743. /// Currently, we check if the function object implements the interface
  744. /// that supports calling with 'this'. If not, the 'this' object is dropped
  745. /// and a normal call is made.
  746. /// </summary>
  747. public static object CallWithContextAndThis(CodeContext/*!*/ context, object func, object instance, params object[] args) {
  748. // drop the 'this' and make the call
  749. return CallWithContext(context, func, args);
  750. }
  751. public static object ToPythonType(PythonType dt) {
  752. if (dt != null) {
  753. return ((object)dt.OldClass) ?? ((object)dt);
  754. }
  755. return null;
  756. }
  757. public static object CallWithArgsTupleAndContext(CodeContext/*!*/ context, object func, object[] args, object argsTuple) {
  758. PythonTuple tp = argsTuple as PythonTuple;
  759. if (tp != null) {
  760. object[] nargs = new object[args.Length + tp.__len__()];
  761. for (int i = 0; i < args.Length; i++) nargs[i] = args[i];
  762. for (int i = 0; i < tp.__len__(); i++) nargs[i + args.Length] = tp[i];
  763. return CallWithContext(context, func, nargs);
  764. }
  765. List allArgs = PythonOps.MakeEmptyList(args.Length + 10);
  766. allArgs.AddRange(args);
  767. IEnumerator e = PythonOps.GetEnumerator(argsTuple);
  768. while (e.MoveNext()) allArgs.AddNoLock(e.Current);
  769. return CallWithContext(context, func, allArgs.GetObjectArray());
  770. }
  771. [Obsolete("Use ObjectOpertaions instead")]
  772. public static object CallWithArgsTupleAndKeywordDictAndContext(CodeContext/*!*/ context, object func, object[] args, string[] names, object argsTuple, object kwDict) {
  773. IDictionary kws = kwDict as IDictionary;
  774. if (kws == null && kwDict != null) throw PythonOps.TypeError("argument after ** must be a dictionary");
  775. if ((kws == null || kws.Count == 0) && names.Length == 0) {
  776. List<object> largs = new List<object>(args);
  777. if (argsTuple != null) {
  778. foreach (object arg in PythonOps.GetCollection(argsTuple))
  779. largs.Add(arg);
  780. }
  781. return CallWithContext(context, func, largs.ToArray());
  782. } else {
  783. List<object> largs;
  784. if (argsTuple != null && args.Length == names.Length) {
  785. PythonTuple tuple = argsTuple as PythonTuple;
  786. if (tuple == null) tuple = new PythonTuple(argsTuple);
  787. largs = new List<object>(tuple);
  788. largs.AddRange(args);
  789. } else {
  790. largs = new List<object>(args);
  791. if (argsTuple != null) {
  792. largs.InsertRange(args.Length - names.Length, PythonTuple.Make(argsTuple));
  793. }
  794. }
  795. List<string> lnames = new List<string>(names);
  796. if (kws != null) {
  797. IDictionaryEnumerator ide = kws.GetEnumerator();
  798. while (ide.MoveNext()) {
  799. lnames.Add((string)ide.Key);
  800. largs.Add(ide.Value);
  801. }
  802. }
  803. return PythonCalls.CallWithKeywordArgs(context, func, largs.ToArray(), lnames.ToArray());
  804. }
  805. }
  806. public static object CallWithKeywordArgs(CodeContext/*!*/ context, object func, object[] args, string[] names) {
  807. return PythonCalls.CallWithKeywordArgs(context, func, args, names);
  808. }
  809. public static object CallWithArgsTuple(object func, object[] args, object argsTuple) {
  810. PythonTuple tp = argsTuple as PythonTuple;
  811. if (tp != null) {
  812. object[] nargs = new object[args.Length + tp.__len__()];
  813. for (int i = 0; i < args.Length; i++) nargs[i] = args[i];
  814. for (int i = 0; i < tp.__len__(); i++) nargs[i + args.Length] = tp[i];
  815. return PythonCalls.Call(func, nargs);
  816. }
  817. List allArgs = PythonOps.MakeEmptyList(args.Length + 10);
  818. allArgs.AddRange(args);
  819. IEnumerator e = PythonOps.GetEnumerator(argsTuple);
  820. while (e.MoveNext()) allArgs.AddNoLock(e.Current);
  821. return PythonCalls.Call(func, allArgs.GetObjectArray());
  822. }
  823. public static object GetIndex(CodeContext/*!*/ context, object o, object index) {
  824. PythonContext pc = PythonContext.GetContext(context);
  825. return pc.GetIndexSite.Target(pc.GetIndexSite, o, index);
  826. }
  827. public static bool TryGetBoundAttr(object o, string name, out object ret) {
  828. return TryGetBoundAttr(DefaultContext.Default, o, name, out ret);
  829. }
  830. public static void SetAttr(CodeContext/*!*/ context, object o, string name, object value) {
  831. PythonContext.GetContext(context).SetAttr(context, o, name, value);
  832. }
  833. public static bool TryGetBoundAttr(CodeContext/*!*/ context, object o, string name, out object ret) {
  834. return DynamicHelpers.GetPythonType(o).TryGetBoundAttr(context, o, name, out ret);
  835. }
  836. public static void DeleteAttr(CodeContext/*!*/ context, object o, string name) {
  837. PythonContext.GetContext(context).DeleteAttr(context, o, name);
  838. }
  839. public static bool HasAttr(CodeContext/*!*/ context, object o, string name) {
  840. object dummy;
  841. try {
  842. return TryGetBoundAttr(context, o, name, out dummy);
  843. } catch (SystemExitException) {
  844. throw;
  845. } catch (KeyboardInterruptException) {
  846. // we don't catch ThreadAbortException because it will
  847. // automatically re-throw on it's own.
  848. throw;
  849. } catch {
  850. return false;
  851. }
  852. }
  853. public static object GetBoundAttr(CodeContext/*!*/ context, object o, string name) {
  854. object ret;
  855. if (!DynamicHelpers.GetPythonType(o).TryGetBoundAttr(context, o, name, out ret)) {
  856. if (o is OldClass) {
  857. throw PythonOps.AttributeError("type object '{0}' has no attribute '{1}'",
  858. ((OldClass)o).Name, name);
  859. } else {
  860. throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'", PythonTypeOps.GetName(o), name);
  861. }
  862. }
  863. return ret;
  864. }
  865. public static void ObjectSetAttribute(CodeContext/*!*/ context, object o, string name, object value) {
  866. if (!DynamicHelpers.GetPythonType(o).TrySetNonCustomMember(context, o, name, value))
  867. throw AttributeErrorForMissingOrReadonly(context, DynamicHelpers.GetPythonType(o), name);
  868. }
  869. public static void ObjectDeleteAttribute(CodeContext/*!*/ context, object o, string name) {
  870. if (!DynamicHelpers.GetPythonType(o).TryDeleteNonCustomMember(context, o, name)) {
  871. throw AttributeErrorForMissingOrReadonly(context, DynamicHelpers.GetPythonType(o), name);
  872. }
  873. }
  874. public static object ObjectGetAttribute(CodeContext/*!*/ context, object o, string name) {
  875. OldClass oc = o as OldClass;
  876. if (oc != null) {
  877. return oc.GetMember(context, name);
  878. }
  879. object value;
  880. if (DynamicHelpers.GetPythonType(o).TryGetNonCustomMember(context, o, name, out value)) {
  881. return value;
  882. }
  883. throw PythonOps.AttributeErrorForObjectMissingAttribute(o, name);
  884. }
  885. internal static IList<string> GetStringMemberList(IPythonMembersList pyMemList) {
  886. List<string> res = new List<string>();
  887. foreach (object o in pyMemList.GetMemberNames(DefaultContext.Default)) {
  888. if (o is string) {
  889. res.Add((string)o);
  890. }
  891. }
  892. return res;
  893. }
  894. public static IList<object> GetAttrNames(CodeContext/*!*/ context, object o) {
  895. IPythonMembersList pyMemList = o as IPythonMembersList;
  896. if (pyMemList != null) {
  897. return pyMemList.GetMemberNames(context);
  898. }
  899. IMembersList memList = o as IMembersList;
  900. if (memList != null) {
  901. return new List(memList.GetMemberNames());
  902. }
  903. IPythonObject po = o as IPythonObject;
  904. if (po != null) {
  905. return po.PythonType.GetMemberNames(context, o);
  906. }
  907. List res = DynamicHelpers.GetPythonType(o).GetMemberNames(context, o);
  908. #if !SILVERLIGHT
  909. if (o != null && Microsoft.Scripting.ComInterop.ComBinder.IsComObject(o)) {
  910. foreach (string name in Microsoft.Scripting.ComInterop.ComBinder.GetDynamicMemberNames(o)) {
  911. if (!res.Contains(name)) {
  912. res.AddNoLock(name);
  913. }
  914. }
  915. }
  916. #endif
  917. return res;
  918. }
  919. /// <summary>
  920. /// Called from generated code emitted by NewTypeMaker.
  921. /// </summary>
  922. public static void CheckInitializedAttribute(object o, object self, string name) {
  923. if (o == Uninitialized.Instance) {
  924. throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'",
  925. PythonTypeOps.GetName(self),
  926. name);
  927. }
  928. }
  929. public static object GetUserSlotValue(CodeContext context, PythonTypeUserDescriptorSlot slot, object instance, PythonType type) {
  930. return slot.GetValue(context, instance, type);
  931. }
  932. /// <summary>
  933. /// Handles the descriptor protocol for user-defined objects that may implement __get__
  934. /// </summary>
  935. public static object GetUserDescriptor(object o, object instance, object context) {
  936. if (o is IPythonObject) {
  937. // slow, but only encountred for user defined descriptors.
  938. PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__get__");
  939. object ret;
  940. if (PythonContext.TryInvokeTernaryOperator(DefaultContext.Default,
  941. TernaryOperators.GetDescriptor,
  942. o,
  943. instance,
  944. context,
  945. out ret)) {
  946. return ret;
  947. }
  948. }
  949. return o;
  950. }
  951. /// <summary>
  952. /// Handles the descriptor protocol for user-defined objects that may implement __set__
  953. /// </summary>
  954. public static bool TrySetUserDescriptor(object o, object instance, object value) {
  955. if (o != null && o.GetType() == typeof(OldInstance)) return false; // only new-style classes have descriptors
  956. // slow, but only encountred for user defined descriptors.
  957. PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__set__");
  958. object dummy;
  959. return PythonContext.TryInvokeTernaryOperator(DefaultContext.Default,
  960. TernaryOperators.SetDescriptor,
  961. o,
  962. instance,
  963. value,
  964. out dummy);
  965. }
  966. /// <summary>
  967. /// Handles the descriptor protocol for user-defined objects that may implement __delete__
  968. /// </summary>
  969. public static bool TryDeleteUserDescriptor(object o, object instance) {
  970. if (o != null && o.GetType() == typeof(OldInstance)) return false; // only new-style classes can have descriptors
  971. // slow, but only encountred for user defined descriptors.
  972. PerfTrack.NoteEvent(PerfTrack.Categories.DictInvoke, "__delete__");
  973. object dummy;
  974. return PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default,
  975. o,
  976. instance,
  977. "__delete__",
  978. out dummy);
  979. }
  980. public static object Invoke(CodeContext/*!*/ context, object target, string name, params object[] args) {
  981. return PythonCalls.Call(context, PythonOps.GetBoundAttr(context, target, name), args);
  982. }
  983. public static Delegate CreateDynamicDelegate(DynamicMethod meth, Type delegateType, object target) {
  984. // Always close delegate around its own instance of the frame
  985. return meth.CreateDelegate(delegateType, target);
  986. }
  987. public static double CheckMath(double v) {
  988. if (double.IsInfi