PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 361 lines | 285 code | 56 blank | 20 comment | 12 complexity | 93a1f9c593bc4fa0daec74189f6981e9 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.Generic;
  22. using System.Dynamic;
  23. using Microsoft.Scripting;
  24. using Microsoft.Scripting.Actions;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime.Operations;
  28. using IronPython.Runtime.Types;
  29. namespace IronPython.Runtime.Binding {
  30. using Ast = Expression;
  31. using AstUtils = Microsoft.Scripting.Ast.Utils;
  32. class MetaOldClass : MetaPythonObject, IPythonInvokable, IPythonGetable, IPythonOperable, IPythonConvertible {
  33. public MetaOldClass(Expression/*!*/ expression, BindingRestrictions/*!*/ restrictions, OldClass/*!*/ value)
  34. : base(expression, BindingRestrictions.Empty, value) {
  35. Assert.NotNull(value);
  36. }
  37. #region IPythonInvokable Members
  38. public DynamicMetaObject/*!*/ Invoke(PythonInvokeBinder/*!*/ pythonInvoke, Expression/*!*/ codeContext, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
  39. return MakeCallRule(pythonInvoke, codeContext, args);
  40. }
  41. #endregion
  42. #region IPythonGetable Members
  43. public DynamicMetaObject GetMember(PythonGetMemberBinder member, DynamicMetaObject codeContext) {
  44. // no codeContext filtering but avoid an extra site by handling this action directly
  45. return MakeGetMember(member, codeContext);
  46. }
  47. #endregion
  48. #region MetaObject Overrides
  49. public override DynamicMetaObject/*!*/ BindInvokeMember(InvokeMemberBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args) {
  50. return BindingHelpers.GenericInvokeMember(action, null, this, args);
  51. }
  52. public override DynamicMetaObject/*!*/ BindInvoke(InvokeBinder/*!*/ call, params DynamicMetaObject/*!*/[]/*!*/ args) {
  53. return MakeCallRule(call, AstUtils.Constant(PythonContext.GetPythonContext(call).SharedContext), args);
  54. }
  55. public override DynamicMetaObject/*!*/ BindCreateInstance(CreateInstanceBinder/*!*/ create, params DynamicMetaObject/*!*/[]/*!*/ args) {
  56. return MakeCallRule(create, AstUtils.Constant(PythonContext.GetPythonContext(create).SharedContext), args);
  57. }
  58. public override DynamicMetaObject/*!*/ BindGetMember(GetMemberBinder/*!*/ member) {
  59. return MakeGetMember(member, PythonContext.GetCodeContextMO(member));
  60. }
  61. public override DynamicMetaObject/*!*/ BindSetMember(SetMemberBinder/*!*/ member, DynamicMetaObject/*!*/ value) {
  62. return MakeSetMember(member.Name, value);
  63. }
  64. public override DynamicMetaObject/*!*/ BindDeleteMember(DeleteMemberBinder/*!*/ member) {
  65. return MakeDeleteMember(member);
  66. }
  67. public override DynamicMetaObject BindConvert(ConvertBinder/*!*/ conversion) {
  68. return ConvertWorker(conversion, conversion.Type, conversion.Explicit ? ConversionResultKind.ExplicitCast : ConversionResultKind.ImplicitCast);
  69. }
  70. public DynamicMetaObject BindConvert(PythonConversionBinder binder) {
  71. return ConvertWorker(binder, binder.Type, binder.ResultKind);
  72. }
  73. public DynamicMetaObject ConvertWorker(DynamicMetaObjectBinder binder, Type toType, ConversionResultKind kind) {
  74. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Convert");
  75. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass Convert");
  76. if (toType.IsSubclassOf(typeof(Delegate))) {
  77. return MakeDelegateTarget(binder, toType, Restrict(typeof(OldClass)));
  78. }
  79. return FallbackConvert(binder);
  80. }
  81. public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames() {
  82. foreach (object o in ((IPythonMembersList)Value).GetMemberNames(DefaultContext.Default)) {
  83. if (o is string) {
  84. yield return (string)o;
  85. }
  86. }
  87. }
  88. #endregion
  89. #region Calls
  90. private DynamicMetaObject/*!*/ MakeCallRule(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject[] args) {
  91. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke w/ " + args.Length + " args");
  92. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass Invoke");
  93. CallSignature signature = BindingHelpers.GetCallSignature(call);
  94. // TODO: If we know __init__ wasn't present we could construct the OldInstance directly.
  95. Expression[] exprArgs = new Expression[args.Length];
  96. for (int i = 0; i < args.Length; i++) {
  97. exprArgs[i] = args[i].Expression;
  98. }
  99. ParameterExpression init = Ast.Variable(typeof(object), "init");
  100. ParameterExpression instTmp = Ast.Variable(typeof(object), "inst");
  101. DynamicMetaObject self = Restrict(typeof(OldClass));
  102. return new DynamicMetaObject(
  103. Ast.Block(
  104. new ParameterExpression[] { init, instTmp },
  105. Ast.Assign(
  106. instTmp,
  107. Ast.New(
  108. typeof(OldInstance).GetConstructor(new Type[] { typeof(CodeContext), typeof(OldClass) }),
  109. codeContext,
  110. self.Expression
  111. )
  112. ),
  113. Ast.Condition(
  114. Ast.Call(
  115. typeof(PythonOps).GetMethod("OldClassTryLookupInit"),
  116. self.Expression,
  117. instTmp,
  118. init
  119. ),
  120. Ast.Dynamic(
  121. PythonContext.GetPythonContext(call).Invoke(
  122. signature
  123. ),
  124. typeof(object),
  125. ArrayUtils.Insert<Expression>(codeContext, init, exprArgs)
  126. ),
  127. NoInitCheckNoArgs(signature, self, args)
  128. ),
  129. instTmp
  130. ),
  131. self.Restrictions.Merge(BindingRestrictions.Combine(args))
  132. );
  133. }
  134. private static Expression NoInitCheckNoArgs(CallSignature signature, DynamicMetaObject self, DynamicMetaObject[] args) {
  135. int unusedCount = args.Length;
  136. Expression dictExpr = GetArgumentExpression(signature, ArgumentType.Dictionary, ref unusedCount, args);
  137. Expression listExpr = GetArgumentExpression(signature, ArgumentType.List, ref unusedCount, args);
  138. if (signature.IsSimple || unusedCount > 0) {
  139. if (args.Length > 0) {
  140. return Ast.Call(
  141. typeof(PythonOps).GetMethod("OldClassMakeCallError"),
  142. self.Expression
  143. );
  144. }
  145. return AstUtils.Constant(null);
  146. }
  147. return Ast.Call(
  148. typeof(PythonOps).GetMethod("OldClassCheckCallError"),
  149. self.Expression,
  150. dictExpr,
  151. listExpr
  152. );
  153. }
  154. private static Expression GetArgumentExpression(CallSignature signature, ArgumentType kind, ref int unusedCount, DynamicMetaObject/*!*/[]/*!*/ args) {
  155. int index = signature.IndexOf(kind);
  156. if (index != -1) {
  157. unusedCount--;
  158. return args[index].Expression;
  159. }
  160. return AstUtils.Constant(null);
  161. }
  162. public static object MakeCallError() {
  163. // Normally, if we have an __init__ method, the method binder detects signature mismatches.
  164. // This can happen when a class does not define __init__ and therefore does not take any arguments.
  165. // Beware that calls like F(*(), **{}) have 2 arguments but they're empty and so it should still
  166. // match against def F().
  167. throw PythonOps.TypeError("this constructor takes no arguments");
  168. }
  169. #endregion
  170. #region Member Access
  171. private DynamicMetaObject/*!*/ MakeSetMember(string/*!*/ name, DynamicMetaObject/*!*/ value) {
  172. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass SetMember");
  173. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass SetMember");
  174. DynamicMetaObject self = Restrict(typeof(OldClass));
  175. Expression call, valueExpr = AstUtils.Convert(value.Expression, typeof(object));
  176. switch (name) {
  177. case "__bases__":
  178. call = Ast.Call(
  179. typeof(PythonOps).GetMethod("OldClassSetBases"),
  180. self.Expression,
  181. valueExpr
  182. );
  183. break;
  184. case "__name__":
  185. call = Ast.Call(
  186. typeof(PythonOps).GetMethod("OldClassSetName"),
  187. self.Expression,
  188. valueExpr
  189. );
  190. break;
  191. case "__dict__":
  192. call = Ast.Call(
  193. typeof(PythonOps).GetMethod("OldClassSetDictionary"),
  194. self.Expression,
  195. valueExpr
  196. );
  197. break;
  198. default:
  199. call = Ast.Call(
  200. typeof(PythonOps).GetMethod("OldClassSetNameHelper"),
  201. self.Expression,
  202. AstUtils.Constant(name),
  203. valueExpr
  204. );
  205. break;
  206. }
  207. return new DynamicMetaObject(
  208. call,
  209. self.Restrictions.Merge(value.Restrictions)
  210. );
  211. }
  212. private DynamicMetaObject/*!*/ MakeDeleteMember(DeleteMemberBinder/*!*/ member) {
  213. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass DeleteMember");
  214. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass DeleteMember");
  215. DynamicMetaObject self = Restrict(typeof(OldClass));
  216. return new DynamicMetaObject(
  217. Ast.Call(
  218. typeof(PythonOps).GetMethod("OldClassDeleteMember"),
  219. AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
  220. self.Expression,
  221. AstUtils.Constant(member.Name)
  222. ),
  223. self.Restrictions
  224. );
  225. }
  226. private DynamicMetaObject/*!*/ MakeGetMember(DynamicMetaObjectBinder/*!*/ member, DynamicMetaObject codeContext) {
  227. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass GetMember");
  228. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass GetMember");
  229. DynamicMetaObject self = Restrict(typeof(OldClass));
  230. Expression target;
  231. string memberName = GetGetMemberName(member);
  232. switch (memberName) {
  233. case "__dict__":
  234. target = Ast.Block(
  235. Ast.Call(
  236. typeof(PythonOps).GetMethod("OldClassDictionaryIsPublic"),
  237. self.Expression
  238. ),
  239. Ast.Call(
  240. typeof(PythonOps).GetMethod("OldClassGetDictionary"),
  241. self.Expression
  242. )
  243. );
  244. break;
  245. case "__bases__":
  246. target = Ast.Call(
  247. typeof(PythonOps).GetMethod("OldClassGetBaseClasses"),
  248. self.Expression
  249. );
  250. break;
  251. case "__name__":
  252. target = Ast.Call(
  253. typeof(PythonOps).GetMethod("OldClassGetName"),
  254. self.Expression
  255. );
  256. break;
  257. default:
  258. ParameterExpression tmp = Ast.Variable(typeof(object), "lookupVal");
  259. return new DynamicMetaObject(
  260. Ast.Block(
  261. new ParameterExpression[] { tmp },
  262. Ast.Condition(
  263. Ast.Call(
  264. typeof(PythonOps).GetMethod("OldClassTryLookupValue"),
  265. AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
  266. self.Expression,
  267. AstUtils.Constant(memberName),
  268. tmp
  269. ),
  270. tmp,
  271. AstUtils.Convert(
  272. GetMemberFallback(this, member, codeContext).Expression,
  273. typeof(object)
  274. )
  275. )
  276. ),
  277. self.Restrictions
  278. );
  279. }
  280. return new DynamicMetaObject(
  281. target,
  282. self.Restrictions
  283. );
  284. }
  285. #endregion
  286. #region Helpers
  287. public new OldClass/*!*/ Value {
  288. get {
  289. return (OldClass)base.Value;
  290. }
  291. }
  292. #endregion
  293. #region IPythonOperable Members
  294. DynamicMetaObject IPythonOperable.BindOperation(PythonOperationBinder action, DynamicMetaObject[] args) {
  295. if (action.Operation == PythonOperationKind.IsCallable) {
  296. return new DynamicMetaObject(
  297. AstUtils.Constant(true),
  298. Restrictions.Merge(BindingRestrictions.GetTypeRestriction(Expression, typeof(OldClass)))
  299. );
  300. }
  301. return null;
  302. }
  303. #endregion
  304. }
  305. }