PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/Binding/PythonOperationBinder.cs

http://github.com/IronLanguages/main
C# | 324 lines | 254 code | 52 blank | 18 comment | 135 complexity | 0fce34d97d5cf19c44443cc091231bfd MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  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. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Dynamic;
  24. using System.Reflection;
  25. using System.Runtime.CompilerServices;
  26. using Microsoft.Scripting.Generation;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. using IronPython.Runtime.Operations;
  30. using IronPython.Runtime.Types;
  31. using AstUtils = Microsoft.Scripting.Ast.Utils;
  32. namespace IronPython.Runtime.Binding {
  33. using Ast = Expression;
  34. class PythonOperationBinder : DynamicMetaObjectBinder, IPythonSite, IExpressionSerializable {
  35. private readonly PythonContext/*!*/ _context;
  36. private readonly PythonOperationKind _operation;
  37. public PythonOperationBinder(PythonContext/*!*/ context, PythonOperationKind/*!*/ operation) {
  38. _context = context;
  39. _operation = operation;
  40. }
  41. public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
  42. IPythonOperable op = target as IPythonOperable;
  43. if (op != null) {
  44. DynamicMetaObject res = op.BindOperation(this, ArrayUtils.Insert(target, args));
  45. if (res != null) {
  46. return res;
  47. }
  48. }
  49. return PythonProtocol.Operation(this, ArrayUtils.Insert(target, args));
  50. }
  51. public override T BindDelegate<T>(CallSite<T> site, object[] args) {
  52. switch(_operation) {
  53. case PythonOperationKind.Hash:
  54. if (CompilerHelpers.GetType(args[0]) == typeof(PythonType)) {
  55. if (typeof(T) == typeof(Func<CallSite, object, int>)) {
  56. return (T)(object)new Func<CallSite, object, int>(HashPythonType);
  57. }
  58. } else if (args[0] is OldClass) {
  59. if (typeof(T) == typeof(Func<CallSite, object, int>)) {
  60. return (T)(object)new Func<CallSite, object, int>(HashOldClass);
  61. }
  62. }
  63. break;
  64. case PythonOperationKind.Compare:
  65. if (CompilerHelpers.GetType(args[0]) == typeof(string) &&
  66. CompilerHelpers.GetType(args[1]) == typeof(string)) {
  67. if (typeof(T) == typeof(Func<CallSite, object, object, int>)) {
  68. return (T)(object)new Func<CallSite, object, object, int>(CompareStrings);
  69. }
  70. }
  71. break;
  72. case PythonOperationKind.GetEnumeratorForIteration:
  73. if (CompilerHelpers.GetType(args[0]) == typeof(List)) {
  74. if (typeof(T) == typeof(Func<CallSite, List, KeyValuePair<IEnumerator, IDisposable>>)) {
  75. return (T)(object)new Func<CallSite, List, KeyValuePair<IEnumerator, IDisposable>>(GetListEnumerator);
  76. }
  77. return (T)(object)new Func<CallSite, object, KeyValuePair<IEnumerator, IDisposable>>(GetListEnumerator);
  78. } else if (CompilerHelpers.GetType(args[0]) == typeof(PythonTuple)) {
  79. if (typeof(T) == typeof(Func<CallSite, PythonTuple, KeyValuePair<IEnumerator, IDisposable>>)) {
  80. return (T)(object)new Func<CallSite, PythonTuple, KeyValuePair<IEnumerator, IDisposable>>(GetTupleEnumerator);
  81. }
  82. return (T)(object)new Func<CallSite, object, KeyValuePair<IEnumerator, IDisposable>>(GetTupleEnumerator);
  83. }
  84. break;
  85. case PythonOperationKind.Contains:
  86. if (CompilerHelpers.GetType(args[1]) == typeof(List)) {
  87. Type tType = typeof(T);
  88. if (tType == typeof(Func<CallSite, object, object, bool>)) {
  89. return (T)(object)new Func<CallSite, object, object, bool>(ListContains<object>);
  90. } else if (tType == typeof(Func<CallSite, object, List, bool>)) {
  91. return (T)(object)new Func<CallSite, object, List, bool>(ListContains);
  92. } else if (tType == typeof(Func<CallSite, int, object, bool>)) {
  93. return (T)(object)new Func<CallSite, int, object, bool>(ListContains<int>);
  94. } else if (tType == typeof(Func<CallSite, string, object, bool>)) {
  95. return (T)(object)new Func<CallSite, string, object, bool>(ListContains<string>);
  96. } else if (tType == typeof(Func<CallSite, double, object, bool>)) {
  97. return (T)(object)new Func<CallSite, double, object, bool>(ListContains<double>);
  98. } else if (tType == typeof(Func<CallSite, PythonTuple, object, bool>)) {
  99. return (T)(object)new Func<CallSite, PythonTuple, object, bool>(ListContains<PythonTuple>);
  100. }
  101. } else if (CompilerHelpers.GetType(args[1]) == typeof(PythonTuple)) {
  102. Type tType = typeof(T);
  103. if (tType == typeof(Func<CallSite, object, object, bool>)) {
  104. return (T)(object)new Func<CallSite, object, object, bool>(TupleContains<object>);
  105. } else if (tType == typeof(Func<CallSite, object, PythonTuple, bool>)) {
  106. return (T)(object)new Func<CallSite, object, PythonTuple, bool>(TupleContains);
  107. } else if (tType == typeof(Func<CallSite, int, object, bool>)) {
  108. return (T)(object)new Func<CallSite, int, object, bool>(TupleContains<int>);
  109. } else if (tType == typeof(Func<CallSite, string, object, bool>)) {
  110. return (T)(object)new Func<CallSite, string, object, bool>(TupleContains<string>);
  111. } else if (tType == typeof(Func<CallSite, double, object, bool>)) {
  112. return (T)(object)new Func<CallSite, double, object, bool>(TupleContains<double>);
  113. } else if (tType == typeof(Func<CallSite, PythonTuple, object, bool>)) {
  114. return (T)(object)new Func<CallSite, PythonTuple, object, bool>(TupleContains<PythonTuple>);
  115. }
  116. } else if (CompilerHelpers.GetType(args[0]) == typeof(string) && CompilerHelpers.GetType(args[1]) == typeof(string)) {
  117. Type tType = typeof(T);
  118. if (tType == typeof(Func<CallSite, object, object, bool>)) {
  119. return (T)(object)new Func<CallSite, object, object, bool>(StringContains);
  120. } else if(tType == typeof(Func<CallSite, string, object, bool>)) {
  121. return (T)(object)new Func<CallSite, string, object, bool>(StringContains);
  122. } else if (tType == typeof(Func<CallSite, object, string, bool>)) {
  123. return (T)(object)new Func<CallSite, object, string, bool>(StringContains);
  124. } else if (tType == typeof(Func<CallSite, string, string, bool>)) {
  125. return (T)(object)new Func<CallSite, string, string, bool>(StringContains);
  126. }
  127. } else if (CompilerHelpers.GetType(args[1]) == typeof(SetCollection)) {
  128. if (typeof(T) == typeof(Func<CallSite, object, object, bool>)) {
  129. return (T)(object)new Func<CallSite, object, object, bool>(SetContains);
  130. }
  131. }
  132. break;
  133. }
  134. return base.BindDelegate<T>(site, args);
  135. }
  136. private KeyValuePair<IEnumerator, IDisposable> GetListEnumerator(CallSite site, List value) {
  137. return new KeyValuePair<IEnumerator,IDisposable>(new ListIterator(value), null);
  138. }
  139. private KeyValuePair<IEnumerator, IDisposable> GetListEnumerator(CallSite site, object value) {
  140. if (value != null && value.GetType() == typeof(List)) {
  141. return new KeyValuePair<IEnumerator,IDisposable>(new ListIterator((List)value), null);
  142. }
  143. return ((CallSite<Func<CallSite, object, KeyValuePair<IEnumerator, IDisposable>>>)site).Update(site, value);
  144. }
  145. private KeyValuePair<IEnumerator, IDisposable> GetTupleEnumerator(CallSite site, PythonTuple value) {
  146. return new KeyValuePair<IEnumerator,IDisposable>(new TupleEnumerator(value), null);
  147. }
  148. private KeyValuePair<IEnumerator, IDisposable> GetTupleEnumerator(CallSite site, object value) {
  149. if (value != null && value.GetType() == typeof(PythonTuple)) {
  150. return new KeyValuePair<IEnumerator, IDisposable>(new TupleEnumerator((PythonTuple)value), null);
  151. }
  152. return ((CallSite<Func<CallSite, object, KeyValuePair<IEnumerator, IDisposable>>>)site).Update(site, value);
  153. }
  154. private bool ListContains(CallSite site, object other, List value) {
  155. return value.ContainsWorker(other);
  156. }
  157. private bool ListContains<TOther>(CallSite site, TOther other, object value) {
  158. if (value != null && value.GetType() == typeof(List)) {
  159. return ((List)value).ContainsWorker(other);
  160. }
  161. return ((CallSite<Func<CallSite, TOther, object, bool>>)site).Update(site, other, value);
  162. }
  163. private bool TupleContains(CallSite site, object other, PythonTuple value) {
  164. return value.Contains(other);
  165. }
  166. private bool TupleContains<TOther>(CallSite site, TOther other, object value) {
  167. if (value != null && value.GetType() == typeof(PythonTuple)) {
  168. return ((PythonTuple)value).Contains(other);
  169. }
  170. return ((CallSite<Func<CallSite, TOther, object, bool>>)site).Update(site, other, value);
  171. }
  172. private bool StringContains(CallSite site, string other, string value) {
  173. if (other != null && value != null) {
  174. return StringOps.__contains__(value, other);
  175. }
  176. return ((CallSite<Func<CallSite, string, string, bool>>)site).Update(site, other, value);
  177. }
  178. private bool StringContains(CallSite site, object other, string value) {
  179. if (other is string && value != null) {
  180. return StringOps.__contains__(value, (string)other);
  181. }
  182. return ((CallSite<Func<CallSite, object, string, bool>>)site).Update(site, other, value);
  183. }
  184. private bool StringContains(CallSite site, string other, object value) {
  185. if (value is string && other != null) {
  186. return StringOps.__contains__((string)value, other);
  187. }
  188. return ((CallSite<Func<CallSite, string, object, bool>>)site).Update(site, other, value);
  189. }
  190. private bool StringContains(CallSite site, object other, object value) {
  191. if (value is string && other is string) {
  192. return StringOps.__contains__((string)value, (string)other);
  193. }
  194. return ((CallSite<Func<CallSite, object, object, bool>>)site).Update(site, other, value);
  195. }
  196. private bool SetContains(CallSite site, object other, object value) {
  197. if (value != null && value.GetType() == typeof(SetCollection)) {
  198. return ((SetCollection)value).__contains__(other);
  199. }
  200. return ((CallSite<Func<CallSite, object, object, bool>>)site).Update(site, other, value);
  201. }
  202. private int HashPythonType(CallSite site, object value) {
  203. if (value != null && value.GetType() == typeof(PythonType)) {
  204. return value.GetHashCode();
  205. }
  206. return ((CallSite<Func<CallSite, object, int>>)site).Update(site, value);
  207. }
  208. private int HashOldClass(CallSite site, object value) {
  209. // OldClass is sealed, an is check is good enough.
  210. if (value is OldClass) {
  211. return value.GetHashCode();
  212. }
  213. return ((CallSite<Func<CallSite, object, int>>)site).Update(site, value);
  214. }
  215. private int CompareStrings(CallSite site, object arg0, object arg1) {
  216. if (arg0 != null && arg0.GetType() == typeof(string) &&
  217. arg1 != null && arg1.GetType() == typeof(string)) {
  218. return StringOps.Compare((string)arg0, (string)arg1);
  219. }
  220. return ((CallSite<Func<CallSite, object, object, int>>)site).Update(site, arg0, arg1);
  221. }
  222. public PythonOperationKind Operation {
  223. get {
  224. return _operation;
  225. }
  226. }
  227. /// <summary>
  228. /// The result type of the operation.
  229. /// </summary>
  230. public override Type ReturnType {
  231. get {
  232. switch (Operation & (~PythonOperationKind.DisableCoerce)) {
  233. case PythonOperationKind.Compare: return typeof(int);
  234. case PythonOperationKind.IsCallable: return typeof(bool);
  235. case PythonOperationKind.Hash: return typeof(int);
  236. case PythonOperationKind.Contains: return typeof(bool);
  237. case PythonOperationKind.GetEnumeratorForIteration: return typeof(KeyValuePair<IEnumerator, IDisposable>);
  238. case PythonOperationKind.CallSignatures: return typeof(IList<string>);
  239. case PythonOperationKind.Documentation: return typeof(string);
  240. }
  241. return typeof(object);
  242. }
  243. }
  244. public override int GetHashCode() {
  245. return base.GetHashCode() ^ _context.Binder.GetHashCode() ^ _operation.GetHashCode();
  246. }
  247. public override bool Equals(object obj) {
  248. PythonOperationBinder ob = obj as PythonOperationBinder;
  249. if (ob == null) {
  250. return false;
  251. }
  252. return ob._context.Binder == _context.Binder && base.Equals(obj);
  253. }
  254. public PythonContext/*!*/ Context {
  255. get {
  256. return _context;
  257. }
  258. }
  259. public override string ToString() {
  260. return "Python " + Operation;
  261. }
  262. #region IExpressionSerializable Members
  263. public Expression CreateExpression() {
  264. return Ast.Call(
  265. typeof(PythonOps).GetMethod("MakeOperationAction"),
  266. BindingHelpers.CreateBinderStateExpression(),
  267. AstUtils.Constant((int)Operation)
  268. );
  269. }
  270. #endregion
  271. }
  272. }