PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

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

http://github.com/IronLanguages/main
C# | 4721 lines | 3456 code | 832 blank | 433 comment | 999 complexity | 75c3ceba55b7efd7911c052402a775cc MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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

Large files files are truncated, but you can click here to view the full file