PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython/Runtime/Binding/MetaMethod.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 301 lines | 219 code | 42 blank | 40 comment | 26 complexity | 35b3302feb966b8f09ad2806fcebe655 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  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. #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 Microsoft.Scripting;
  25. using Microsoft.Scripting.Actions;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime.Operations;
  28. namespace IronPython.Runtime.Binding {
  29. using Ast = Expression;
  30. using AstUtils = Microsoft.Scripting.Ast.Utils;
  31. class MetaMethod : MetaPythonObject, IPythonInvokable, IPythonConvertible {
  32. public MetaMethod(Expression/*!*/ expression, BindingRestrictions/*!*/ restrictions, Method/*!*/ value)
  33. : base(expression, BindingRestrictions.Empty, value) {
  34. Assert.NotNull(value);
  35. }
  36. #region IPythonInvokable Members
  37. public DynamicMetaObject/*!*/ Invoke(PythonInvokeBinder/*!*/ pythonInvoke, Expression/*!*/ codeContext, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
  38. return InvokeWorker(pythonInvoke, args);
  39. }
  40. #endregion
  41. #region MetaObject Overrides
  42. public override DynamicMetaObject/*!*/ BindInvokeMember(InvokeMemberBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args) {
  43. return BindingHelpers.GenericInvokeMember(action, null, this, args);
  44. }
  45. public override DynamicMetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ callAction, params DynamicMetaObject/*!*/[]/*!*/ args) {
  46. return InvokeWorker(callAction, args);
  47. }
  48. public override DynamicMetaObject BindConvert(ConvertBinder/*!*/ conversion) {
  49. return ConvertWorker(conversion, conversion.Type, conversion.Explicit ? ConversionResultKind.ExplicitCast : ConversionResultKind.ImplicitCast);
  50. }
  51. public DynamicMetaObject BindConvert(PythonConversionBinder binder) {
  52. return ConvertWorker(binder, binder.Type, binder.ResultKind);
  53. }
  54. public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) {
  55. if (toType.IsSubclassOf(typeof(Delegate))) {
  56. return MakeDelegateTarget(binder, toType, Restrict(typeof(Method)));
  57. }
  58. return FallbackConvert(binder);
  59. }
  60. #endregion
  61. #region Invoke Implementation
  62. private DynamicMetaObject InvokeWorker(DynamicMetaObjectBinder/*!*/ callAction, DynamicMetaObject/*!*/[] args) {
  63. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Method Invoke " + args.Length);
  64. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Method");
  65. CallSignature signature = BindingHelpers.GetCallSignature(callAction);
  66. DynamicMetaObject self = Restrict(typeof(Method));
  67. BindingRestrictions restrictions = self.Restrictions;
  68. DynamicMetaObject func = GetMetaFunction(self);
  69. DynamicMetaObject call;
  70. if (Value.im_self == null) {
  71. // restrict to null self (Method is immutable so this is an invariant test)
  72. restrictions = restrictions.Merge(
  73. BindingRestrictions.GetExpressionRestriction(
  74. Ast.Equal(
  75. GetSelfExpression(self),
  76. AstUtils.Constant(null)
  77. )
  78. )
  79. );
  80. if (args.Length == 0) {
  81. // this is an error, we pass null which will throw the normal error
  82. call = new DynamicMetaObject(
  83. Ast.Call(
  84. typeof(PythonOps).GetMethod("MethodCheckSelf"),
  85. PythonContext.GetCodeContext(callAction),
  86. self.Expression,
  87. AstUtils.Constant(null)
  88. ),
  89. restrictions
  90. );
  91. } else {
  92. // this may or may not be an error
  93. call = new DynamicMetaObject(
  94. Ast.Block(
  95. MakeCheckSelf(callAction, signature, args),
  96. Ast.Dynamic(
  97. PythonContext.GetPythonContext(callAction).Invoke(
  98. BindingHelpers.GetCallSignature(callAction)
  99. ),
  100. typeof(object),
  101. ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(ArrayUtils.Insert(func, args)))
  102. )
  103. ),
  104. BindingRestrictions.Empty
  105. );
  106. /*call = func.Invoke(callAction, ArrayUtils.Insert(func, args));
  107. call = new MetaObject(
  108. Ast.Comma(
  109. Ast.Call(
  110. typeof(PythonOps).GetMethod("MethodCheckSelf"),
  111. self.Expression,
  112. args[0].Expression
  113. ),
  114. call.Expression
  115. ),
  116. call.Restrictions
  117. );*/
  118. }
  119. } else {
  120. // restrict to non-null self (Method is immutable so this is an invariant test)
  121. restrictions = restrictions.Merge(
  122. BindingRestrictions.GetExpressionRestriction(
  123. Ast.NotEqual(
  124. GetSelfExpression(self),
  125. AstUtils.Constant(null)
  126. )
  127. )
  128. );
  129. DynamicMetaObject im_self = GetMetaSelf(self);
  130. DynamicMetaObject[] newArgs = ArrayUtils.Insert(func, im_self, args);
  131. CallSignature newSig = new CallSignature(ArrayUtils.Insert(new Argument(ArgumentType.Simple), signature.GetArgumentInfos()));
  132. call = new DynamicMetaObject(
  133. Ast.Dynamic(
  134. PythonContext.GetPythonContext(callAction).Invoke(
  135. newSig
  136. ),
  137. typeof(object),
  138. ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(newArgs))
  139. ),
  140. BindingRestrictions.Empty
  141. );
  142. /*
  143. call = func.Invoke(
  144. new CallBinder(
  145. PythonContext.GetBinderState(callAction),
  146. newSig
  147. ),
  148. newArgs
  149. );*/
  150. }
  151. if (call.HasValue) {
  152. return new DynamicMetaObject(
  153. call.Expression,
  154. restrictions.Merge(call.Restrictions),
  155. call.Value
  156. );
  157. } else {
  158. return new DynamicMetaObject(
  159. call.Expression,
  160. restrictions.Merge(call.Restrictions)
  161. );
  162. }
  163. }
  164. #endregion
  165. #region Helpers
  166. private DynamicMetaObject GetMetaSelf(DynamicMetaObject/*!*/ self) {
  167. DynamicMetaObject func;
  168. IDynamicMetaObjectProvider ido = Value.im_self as IDynamicMetaObjectProvider;
  169. if (ido != null) {
  170. func = ido.GetMetaObject(GetSelfExpression(self));
  171. } else if (Value.im_self == null) {
  172. func = new DynamicMetaObject(
  173. GetSelfExpression(self),
  174. BindingRestrictions.Empty);
  175. } else {
  176. func = new DynamicMetaObject(
  177. GetSelfExpression(self),
  178. BindingRestrictions.Empty,
  179. Value.im_self
  180. );
  181. }
  182. return func;
  183. }
  184. private DynamicMetaObject/*!*/ GetMetaFunction(DynamicMetaObject/*!*/ self) {
  185. DynamicMetaObject func;
  186. IDynamicMetaObjectProvider ido = Value.im_func as IDynamicMetaObjectProvider;
  187. if (ido != null) {
  188. func = ido.GetMetaObject(GetFunctionExpression(self));
  189. } else {
  190. func = new DynamicMetaObject(
  191. GetFunctionExpression(self),
  192. BindingRestrictions.Empty
  193. );
  194. }
  195. return func;
  196. }
  197. private static MemberExpression GetFunctionExpression(DynamicMetaObject self) {
  198. return Ast.Property(
  199. self.Expression,
  200. typeof(Method).GetProperty("im_func")
  201. );
  202. }
  203. private static MemberExpression GetSelfExpression(DynamicMetaObject self) {
  204. return Ast.Property(
  205. self.Expression,
  206. typeof(Method).GetProperty("im_self")
  207. );
  208. }
  209. public new Method/*!*/ Value {
  210. get {
  211. return (Method)base.Value;
  212. }
  213. }
  214. private Expression/*!*/ MakeCheckSelf(DynamicMetaObjectBinder/*!*/ binder, CallSignature signature, DynamicMetaObject/*!*/[]/*!*/ args) {
  215. ArgumentType firstArgKind = signature.GetArgumentKind(0);
  216. Expression res;
  217. if (firstArgKind == ArgumentType.Simple || firstArgKind == ArgumentType.Instance) {
  218. res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), args[0].Expression);
  219. } else if (firstArgKind != ArgumentType.List) {
  220. res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), AstUtils.Constant(null));
  221. } else {
  222. // list, check arg[0] and then return original list. If not a list,
  223. // or we have no items, then check against null & throw.
  224. res = CheckSelf(
  225. binder,
  226. AstUtils.Convert(Expression, typeof(Method)),
  227. Ast.Condition(
  228. Ast.AndAlso(
  229. Ast.TypeIs(args[0].Expression, typeof(IList<object>)),
  230. Ast.NotEqual(
  231. Ast.Property(
  232. Ast.Convert(args[0].Expression, typeof(ICollection)),
  233. typeof(ICollection).GetProperty("Count")
  234. ),
  235. AstUtils.Constant(0)
  236. )
  237. ),
  238. Ast.Call(
  239. Ast.Convert(args[0].Expression, typeof(IList<object>)),
  240. typeof(IList<object>).GetMethod("get_Item"),
  241. AstUtils.Constant(0)
  242. ),
  243. AstUtils.Constant(null)
  244. )
  245. );
  246. }
  247. return res;
  248. }
  249. private static Expression/*!*/ CheckSelf(DynamicMetaObjectBinder/*!*/ binder, Expression/*!*/ method, Expression/*!*/ inst) {
  250. return Ast.Call(
  251. typeof(PythonOps).GetMethod("MethodCheckSelf"),
  252. PythonContext.GetCodeContext(binder),
  253. method,
  254. AstUtils.Convert(inst, typeof(object))
  255. );
  256. }
  257. #endregion
  258. }
  259. }