PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_Main/Languages/IronPython/IronPython/Runtime/Binding/MetaOldClass.cs

#
C# | 375 lines | 299 code | 56 blank | 20 comment | 12 complexity | 90dd4c90429a39fef0383ae4d8bc8c1b MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  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. #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. Expression.Not(
  115. Expression.TypeIs(
  116. Expression.Assign(
  117. init,
  118. Ast.Call(
  119. typeof(PythonOps).GetMethod("OldClassTryLookupInit"),
  120. self.Expression,
  121. instTmp
  122. )
  123. ),
  124. typeof(OperationFailed)
  125. )
  126. ),
  127. Ast.Dynamic(
  128. PythonContext.GetPythonContext(call).Invoke(
  129. signature
  130. ),
  131. typeof(object),
  132. ArrayUtils.Insert<Expression>(codeContext, init, exprArgs)
  133. ),
  134. NoInitCheckNoArgs(signature, self, args)
  135. ),
  136. instTmp
  137. ),
  138. self.Restrictions.Merge(BindingRestrictions.Combine(args))
  139. );
  140. }
  141. private static Expression NoInitCheckNoArgs(CallSignature signature, DynamicMetaObject self, DynamicMetaObject[] args) {
  142. int unusedCount = args.Length;
  143. Expression dictExpr = GetArgumentExpression(signature, ArgumentType.Dictionary, ref unusedCount, args);
  144. Expression listExpr = GetArgumentExpression(signature, ArgumentType.List, ref unusedCount, args);
  145. if (signature.IsSimple || unusedCount > 0) {
  146. if (args.Length > 0) {
  147. return Ast.Call(
  148. typeof(PythonOps).GetMethod("OldClassMakeCallError"),
  149. self.Expression
  150. );
  151. }
  152. return AstUtils.Constant(null);
  153. }
  154. return Ast.Call(
  155. typeof(PythonOps).GetMethod("OldClassCheckCallError"),
  156. self.Expression,
  157. dictExpr,
  158. listExpr
  159. );
  160. }
  161. private static Expression GetArgumentExpression(CallSignature signature, ArgumentType kind, ref int unusedCount, DynamicMetaObject/*!*/[]/*!*/ args) {
  162. int index = signature.IndexOf(kind);
  163. if (index != -1) {
  164. unusedCount--;
  165. return args[index].Expression;
  166. }
  167. return AstUtils.Constant(null);
  168. }
  169. public static object MakeCallError() {
  170. // Normally, if we have an __init__ method, the method binder detects signature mismatches.
  171. // This can happen when a class does not define __init__ and therefore does not take any arguments.
  172. // Beware that calls like F(*(), **{}) have 2 arguments but they're empty and so it should still
  173. // match against def F().
  174. throw PythonOps.TypeError("this constructor takes no arguments");
  175. }
  176. #endregion
  177. #region Member Access
  178. private DynamicMetaObject/*!*/ MakeSetMember(string/*!*/ name, DynamicMetaObject/*!*/ value) {
  179. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass SetMember");
  180. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass SetMember");
  181. DynamicMetaObject self = Restrict(typeof(OldClass));
  182. Expression call, valueExpr = AstUtils.Convert(value.Expression, typeof(object));
  183. switch (name) {
  184. case "__bases__":
  185. call = Ast.Call(
  186. typeof(PythonOps).GetMethod("OldClassSetBases"),
  187. self.Expression,
  188. valueExpr
  189. );
  190. break;
  191. case "__name__":
  192. call = Ast.Call(
  193. typeof(PythonOps).GetMethod("OldClassSetName"),
  194. self.Expression,
  195. valueExpr
  196. );
  197. break;
  198. case "__dict__":
  199. call = Ast.Call(
  200. typeof(PythonOps).GetMethod("OldClassSetDictionary"),
  201. self.Expression,
  202. valueExpr
  203. );
  204. break;
  205. default:
  206. call = Ast.Call(
  207. typeof(PythonOps).GetMethod("OldClassSetNameHelper"),
  208. self.Expression,
  209. AstUtils.Constant(name),
  210. valueExpr
  211. );
  212. break;
  213. }
  214. return new DynamicMetaObject(
  215. call,
  216. self.Restrictions.Merge(value.Restrictions)
  217. );
  218. }
  219. private DynamicMetaObject/*!*/ MakeDeleteMember(DeleteMemberBinder/*!*/ member) {
  220. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass DeleteMember");
  221. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass DeleteMember");
  222. DynamicMetaObject self = Restrict(typeof(OldClass));
  223. return new DynamicMetaObject(
  224. Ast.Call(
  225. typeof(PythonOps).GetMethod("OldClassDeleteMember"),
  226. AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
  227. self.Expression,
  228. AstUtils.Constant(member.Name)
  229. ),
  230. self.Restrictions
  231. );
  232. }
  233. private DynamicMetaObject/*!*/ MakeGetMember(DynamicMetaObjectBinder/*!*/ member, DynamicMetaObject codeContext) {
  234. PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass GetMember");
  235. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass GetMember");
  236. DynamicMetaObject self = Restrict(typeof(OldClass));
  237. Expression target;
  238. string memberName = GetGetMemberName(member);
  239. switch (memberName) {
  240. case "__dict__":
  241. target = Ast.Block(
  242. Ast.Call(
  243. typeof(PythonOps).GetMethod("OldClassDictionaryIsPublic"),
  244. self.Expression
  245. ),
  246. Ast.Call(
  247. typeof(PythonOps).GetMethod("OldClassGetDictionary"),
  248. self.Expression
  249. )
  250. );
  251. break;
  252. case "__bases__":
  253. target = Ast.Call(
  254. typeof(PythonOps).GetMethod("OldClassGetBaseClasses"),
  255. self.Expression
  256. );
  257. break;
  258. case "__name__":
  259. target = Ast.Call(
  260. typeof(PythonOps).GetMethod("OldClassGetName"),
  261. self.Expression
  262. );
  263. break;
  264. default:
  265. ParameterExpression tmp = Ast.Variable(typeof(object), "lookupVal");
  266. return new DynamicMetaObject(
  267. Ast.Block(
  268. new ParameterExpression[] { tmp },
  269. Ast.Condition(
  270. Expression.Not(
  271. Expression.TypeIs(
  272. Expression.Assign(
  273. tmp,
  274. Ast.Call(
  275. typeof(PythonOps).GetMethod("OldClassTryLookupValue"),
  276. AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
  277. self.Expression,
  278. AstUtils.Constant(memberName)
  279. )
  280. ),
  281. typeof(OperationFailed)
  282. )
  283. ),
  284. tmp,
  285. AstUtils.Convert(
  286. GetMemberFallback(this, member, codeContext).Expression,
  287. typeof(object)
  288. )
  289. )
  290. ),
  291. self.Restrictions
  292. );
  293. }
  294. return new DynamicMetaObject(
  295. target,
  296. self.Restrictions
  297. );
  298. }
  299. #endregion
  300. #region Helpers
  301. public new OldClass/*!*/ Value {
  302. get {
  303. return (OldClass)base.Value;
  304. }
  305. }
  306. #endregion
  307. #region IPythonOperable Members
  308. DynamicMetaObject IPythonOperable.BindOperation(PythonOperationBinder action, DynamicMetaObject[] args) {
  309. if (action.Operation == PythonOperationKind.IsCallable) {
  310. return new DynamicMetaObject(
  311. AstUtils.Constant(true),
  312. Restrictions.Merge(BindingRestrictions.GetTypeRestriction(Expression, typeof(OldClass)))
  313. );
  314. }
  315. return null;
  316. }
  317. #endregion
  318. }
  319. }