PageRenderTime 50ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/williamybs/uidipythontool
C# | 749 lines | 583 code | 127 blank | 39 comment | 182 complexity | d724716c5d36f4545b3d259449fd8cb3 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.Diagnostics;
  22. using System.Dynamic;
  23. using System.Reflection;
  24. using System.Runtime.CompilerServices;
  25. using System.Text;
  26. using Microsoft.Scripting;
  27. using Microsoft.Scripting.Actions;
  28. using Microsoft.Scripting.Generation;
  29. using Microsoft.Scripting.Interpreter;
  30. using Microsoft.Scripting.Runtime;
  31. using Microsoft.Scripting.Utils;
  32. using IronPython.Runtime.Operations;
  33. using IronPython.Runtime.Types;
  34. namespace IronPython.Runtime.Binding {
  35. using Ast = Expression;
  36. using AstUtils = Microsoft.Scripting.Ast.Utils;
  37. class PythonGetMemberBinder : DynamicMetaObjectBinder, IPythonSite, IExpressionSerializable {
  38. private readonly PythonContext/*!*/ _context;
  39. private readonly GetMemberOptions _options;
  40. private readonly string _name;
  41. public PythonGetMemberBinder(PythonContext/*!*/ context, string/*!*/ name) {
  42. _context = context;
  43. _name = name;
  44. }
  45. public PythonGetMemberBinder(PythonContext/*!*/ context, string/*!*/ name, bool isNoThrow)
  46. : this(context, name) {
  47. _options = isNoThrow ? GetMemberOptions.IsNoThrow : GetMemberOptions.None;
  48. }
  49. #region MetaAction overrides
  50. /// <summary>
  51. /// Python's Invoke is a non-standard action. Here we first try to bind through a Python
  52. /// internal interface (IPythonInvokable) which supports CallSigantures. If that fails
  53. /// and we have an IDO then we translate to the DLR protocol through a nested dynamic site -
  54. /// this includes unsplatting any keyword / position arguments. Finally if it's just a plain
  55. /// old .NET type we use the default binder which supports CallSignatures.
  56. /// </summary>
  57. public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args) {
  58. Debug.Assert(args.Length == 1);
  59. Debug.Assert(args[0].GetLimitType() == typeof(CodeContext));
  60. // we don't have CodeContext if an IDO falls back to us when we ask them to produce the Call
  61. DynamicMetaObject cc = args[0];
  62. IPythonGetable icc = target as IPythonGetable;
  63. if (icc != null) {
  64. // get the member using our interface which also supports CodeContext.
  65. return icc.GetMember(this, cc);
  66. } else if (target.Value is IDynamicMetaObjectProvider) {
  67. return GetForeignObject(target);
  68. }
  69. #if !SILVERLIGHT
  70. else if (Microsoft.Scripting.ComInterop.ComBinder.IsComObject(target.Value)) {
  71. return GetForeignObject(target);
  72. }
  73. #endif
  74. return Fallback(target, cc);
  75. }
  76. public override T BindDelegate<T>(CallSite<T> site, object[] args) {
  77. Debug.Assert(args[1].GetType() == typeof(CodeContext));
  78. IFastGettable fastGet = args[0] as IFastGettable;
  79. if (fastGet != null) {
  80. T res = fastGet.MakeGetBinding<T>(site, this, (CodeContext)args[1], Name);
  81. if (res != null) {
  82. PerfTrack.NoteEvent(PerfTrack.Categories.BindingFast, "IFastGettable");
  83. return res;
  84. }
  85. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "IFastGettable");
  86. return base.BindDelegate<T>(site, args);
  87. }
  88. IPythonObject pyObj = args[0] as IPythonObject;
  89. if (pyObj != null && !(args[0] is IProxyObject)) {
  90. FastBindResult<T> res = UserTypeOps.MakeGetBinding<T>((CodeContext)args[1], site, pyObj, this);
  91. if (res.Target != null) {
  92. PerfTrack.NoteEvent(PerfTrack.Categories.BindingFast, "IPythonObject");
  93. if (res.ShouldCache) {
  94. CacheTarget(res.Target);
  95. }
  96. return res.Target;
  97. }
  98. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "IPythonObject Get");
  99. return base.BindDelegate<T>(site, args);
  100. }
  101. if (args[0] != null) {
  102. if (args[0].GetType() == typeof(PythonModule)) {
  103. if (!IsNoThrow) {
  104. return (T)(object)new Func<CallSite, object, CodeContext, object>(new PythonModuleDelegate(_name).Target);
  105. } else {
  106. return (T)(object)new Func<CallSite, object, CodeContext, object>(new PythonModuleDelegate(_name).NoThrowTarget);
  107. }
  108. } else if (args[0].GetType() == typeof(NamespaceTracker)) {
  109. switch (Name) {
  110. case "__str__":
  111. case "__repr__":
  112. case "__doc__":
  113. // need to return the built in method descriptor for these...
  114. break;
  115. case "__file__":
  116. return (T)(object)new Func<CallSite, object, CodeContext, object>(new NamespaceTrackerDelegate(_name).GetFile);
  117. case "__dict__":
  118. return (T)(object)new Func<CallSite, object, CodeContext, object>(new NamespaceTrackerDelegate(_name).GetDict);
  119. case "__name__":
  120. return (T)(object)new Func<CallSite, object, CodeContext, object>(new NamespaceTrackerDelegate(_name).GetName);
  121. default:
  122. if (IsNoThrow) {
  123. return (T)(object)new Func<CallSite, object, CodeContext, object>(new NamespaceTrackerDelegate(_name).NoThrowTarget);
  124. } else {
  125. return (T)(object)new Func<CallSite, object, CodeContext, object>(new NamespaceTrackerDelegate(_name).Target);
  126. }
  127. }
  128. }
  129. }
  130. if (args[0] != null &&
  131. #if !SILVERLIGHT
  132. !Microsoft.Scripting.ComInterop.ComBinder.IsComObject(args[0]) &&
  133. #endif
  134. !(args[0] is IDynamicMetaObjectProvider)) {
  135. Type selfType = typeof(T).GetMethod("Invoke").GetParameters()[1].ParameterType;
  136. T res = null;
  137. if (selfType == typeof(object)) {
  138. res = (T)(object)MakeGetMemberTarget<object>(Name, args[0]);
  139. } else if (selfType == typeof(List)) {
  140. res = (T)(object)MakeGetMemberTarget<List>(Name, args[0]);
  141. } else if (selfType == typeof(string)) {
  142. res = (T)(object)MakeGetMemberTarget<string>(Name, args[0]);
  143. }
  144. if (res != null) {
  145. return (T)(object)res;
  146. }
  147. return base.BindDelegate<T>(site, args);
  148. }
  149. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast " + IsNoThrow + " " + CompilerHelpers.GetType(args[0]));
  150. return base.BindDelegate<T>(site, args);
  151. }
  152. class FastErrorGet<TSelfType> : FastGetBase {
  153. private readonly Type _type;
  154. private readonly string _name;
  155. public FastErrorGet(Type type, string name) {
  156. _type = type;
  157. _name = name;
  158. }
  159. public override bool IsValid(PythonType type) {
  160. // only used for built-in types, we never become invalid.
  161. return true;
  162. }
  163. public object GetError(CallSite site, TSelfType target, CodeContext context) {
  164. if (target != null && target.GetType() == _type) {
  165. throw PythonOps.AttributeErrorForObjectMissingAttribute(target, _name);
  166. }
  167. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  168. }
  169. public object GetErrorNoThrow(CallSite site, TSelfType target, CodeContext context) {
  170. if (target != null && target.GetType() == _type) {
  171. return OperationFailed.Value;
  172. }
  173. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  174. }
  175. public object GetAmbiguous(CallSite site, TSelfType target, CodeContext context) {
  176. if (target != null && target.GetType() == _type) {
  177. throw new AmbiguousMatchException(_name);
  178. }
  179. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  180. }
  181. }
  182. class BuiltinBase<TSelfType> : FastGetBase {
  183. public override bool IsValid(PythonType type) {
  184. // only used for built-in types, we never become invalid.
  185. return true;
  186. }
  187. }
  188. class FastMethodGet<TSelfType> : BuiltinBase<TSelfType> {
  189. private readonly Type _type;
  190. private readonly BuiltinMethodDescriptor _method;
  191. public FastMethodGet(Type type, BuiltinMethodDescriptor method) {
  192. _type = type;
  193. _method = method;
  194. }
  195. public object GetMethod(CallSite site, TSelfType target, CodeContext context) {
  196. if (target != null && target.GetType() == _type) {
  197. return _method.UncheckedGetAttribute(target);
  198. }
  199. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  200. }
  201. }
  202. class FastSlotGet<TSelfType> : BuiltinBase<TSelfType> {
  203. private readonly Type _type;
  204. private readonly PythonTypeSlot _slot;
  205. private readonly PythonType _owner;
  206. public FastSlotGet(Type type, PythonTypeSlot slot, PythonType owner) {
  207. _type = type;
  208. _slot = slot;
  209. _owner = owner;
  210. }
  211. public object GetRetSlot(CallSite site, TSelfType target, CodeContext context) {
  212. if (target != null && target.GetType() == _type) {
  213. return _slot;
  214. }
  215. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  216. }
  217. public object GetBindSlot(CallSite site, TSelfType target, CodeContext context) {
  218. if (target != null && target.GetType() == _type) {
  219. object value;
  220. _slot.TryGetValue(context, target, _owner, out value);
  221. return value;
  222. }
  223. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  224. }
  225. }
  226. class FastTypeGet<TSelfType> : BuiltinBase<TSelfType> {
  227. private readonly Type _type;
  228. private readonly object _pyType;
  229. public FastTypeGet(Type type, object pythonType) {
  230. _type = type;
  231. _pyType = pythonType;
  232. }
  233. public object GetTypeObject(CallSite site, TSelfType target, CodeContext context) {
  234. if (target != null && target.GetType() == _type) {
  235. return _pyType;
  236. }
  237. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  238. }
  239. }
  240. class FastPropertyGet<TSelfType> : BuiltinBase<TSelfType> {
  241. private readonly Type _type;
  242. private readonly Func<object, object> _propGetter;
  243. public FastPropertyGet(Type type, Func<object, object> propGetter) {
  244. _type = type;
  245. _propGetter = propGetter;
  246. }
  247. public object GetProperty(CallSite site, TSelfType target, CodeContext context) {
  248. if (target != null && target.GetType() == _type) {
  249. return _propGetter(target);
  250. }
  251. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  252. }
  253. public object GetPropertyBool(CallSite site, TSelfType target, CodeContext context) {
  254. if (target != null && target.GetType() == _type) {
  255. return ScriptingRuntimeHelpers.BooleanToObject((bool)_propGetter(target));
  256. }
  257. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  258. }
  259. public object GetPropertyInt(CallSite site, TSelfType target, CodeContext context) {
  260. if (target != null && target.GetType() == _type) {
  261. return ScriptingRuntimeHelpers.Int32ToObject((int)_propGetter(target));
  262. }
  263. return ((CallSite<Func<CallSite, TSelfType, CodeContext, object>>)site).Update(site, target, context);
  264. }
  265. }
  266. private Func<CallSite, TSelfType, CodeContext, object> MakeGetMemberTarget<TSelfType>(string name, object target) {
  267. Type type = CompilerHelpers.GetType(target);
  268. // needed for GetMember call until DynamicAction goes away
  269. if (typeof(TypeTracker).IsAssignableFrom(type)) {
  270. // no fast path for TypeTrackers
  271. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast TypeTracker");
  272. return null;
  273. }
  274. MemberGroup members = Context.Binder.GetMember(MemberRequestKind.Get, type, name);
  275. if (members.Count == 0 && type.IsInterface) {
  276. // all interfaces have object members
  277. type = typeof(object);
  278. members = Context.Binder.GetMember(MemberRequestKind.Get, type, name);
  279. }
  280. if (members.Count == 0 && typeof(IStrongBox).IsAssignableFrom(type)) {
  281. // no fast path for strong box access
  282. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast StrongBox");
  283. return null;
  284. }
  285. MethodInfo getMem = Context.Binder.GetMethod(type, "GetCustomMember");
  286. if (getMem != null && getMem.IsSpecialName) {
  287. // no fast path for custom member access
  288. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetCustomMember " + type);
  289. return null;
  290. }
  291. Expression error;
  292. TrackerTypes memberType = Context.Binder.GetMemberType(members, out error);
  293. if (error == null) {
  294. PythonType argType = DynamicHelpers.GetPythonTypeFromType(type);
  295. bool isHidden = argType.IsHiddenMember(name);
  296. if (isHidden) {
  297. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast FilteredMember " + memberType);
  298. return null;
  299. }
  300. switch (memberType) {
  301. case TrackerTypes.TypeGroup:
  302. case TrackerTypes.Type:
  303. object typeObj;
  304. if (members.Count == 1) {
  305. typeObj = DynamicHelpers.GetPythonTypeFromType(((TypeTracker)members[0]).Type);
  306. } else {
  307. TypeTracker typeTracker = (TypeTracker)members[0];
  308. for (int i = 1; i < members.Count; i++) {
  309. typeTracker = TypeGroup.UpdateTypeEntity(typeTracker, (TypeTracker)members[i]);
  310. }
  311. typeObj = typeTracker;
  312. }
  313. return new FastTypeGet<TSelfType>(type, typeObj).GetTypeObject;
  314. case TrackerTypes.Method:
  315. PythonTypeSlot slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding);
  316. if (slot is BuiltinMethodDescriptor) {
  317. return new FastMethodGet<TSelfType>(type, (BuiltinMethodDescriptor)slot).GetMethod;
  318. } else if (slot is BuiltinFunction) {
  319. return new FastSlotGet<TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetRetSlot;
  320. }
  321. return new FastSlotGet<TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(type)).GetBindSlot;
  322. case TrackerTypes.Event:
  323. if (members.Count == 1 && !((EventTracker)members[0]).IsStatic) {
  324. slot = PythonTypeOps.GetSlot(members, name, _context.DomainManager.Configuration.PrivateBinding);
  325. return new FastSlotGet<TSelfType>(type, slot, DynamicHelpers.GetPythonTypeFromType(((EventTracker)members[0]).DeclaringType)).GetBindSlot;
  326. }
  327. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Event " + members.Count + " " + ((EventTracker)members[0]).IsStatic);
  328. return null;
  329. case TrackerTypes.Property:
  330. if (members.Count == 1) {
  331. PropertyTracker pt = (PropertyTracker)members[0];
  332. if (!pt.IsStatic && pt.GetIndexParameters().Length == 0) {
  333. MethodInfo prop = pt.GetGetMethod();
  334. ParameterInfo[] parameters;
  335. if (prop != null && (parameters = prop.GetParameters()).Length == 0) {
  336. if (prop.ReturnType == typeof(bool)) {
  337. return new FastPropertyGet<TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyBool;
  338. } else if (prop.ReturnType == typeof(int)) {
  339. return new FastPropertyGet<TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetPropertyInt;
  340. } else {
  341. return new FastPropertyGet<TSelfType>(type, CallInstruction.Create(prop, parameters).Invoke).GetProperty;
  342. }
  343. }
  344. }
  345. }
  346. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast Property " + members.Count + " " + ((PropertyTracker)members[0]).IsStatic);
  347. return null;
  348. case TrackerTypes.All:
  349. getMem = Context.Binder.GetMethod(type, "GetBoundMember");
  350. if (getMem != null && getMem.IsSpecialName) {
  351. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast GetBoundMember " + type);
  352. return null;
  353. }
  354. if (IsNoThrow) {
  355. return new FastErrorGet<TSelfType>(type, name).GetErrorNoThrow;
  356. } else {
  357. return new FastErrorGet<TSelfType>(type, name).GetError;
  358. }
  359. default:
  360. PerfTrack.NoteEvent(PerfTrack.Categories.BindingSlow, "GetNoFast " + memberType);
  361. return null;
  362. }
  363. } else {
  364. StringBuilder sb = new StringBuilder();
  365. foreach (MemberTracker mi in members) {
  366. if (sb.Length != 0) sb.Append(", ");
  367. sb.Append(mi.MemberType);
  368. sb.Append(" : ");
  369. sb.Append(mi.ToString());
  370. }
  371. return new FastErrorGet<TSelfType>(type, sb.ToString()).GetAmbiguous;
  372. }
  373. }
  374. class PythonModuleDelegate : FastGetBase {
  375. private readonly string _name;
  376. public PythonModuleDelegate(string name) {
  377. _name = name;
  378. }
  379. public object Target(CallSite site, object self, CodeContext context) {
  380. if (self != null && self.GetType() == typeof(PythonModule)) {
  381. return ((PythonModule)self).__getattribute__(context, _name);
  382. }
  383. return Update(site, self, context);
  384. }
  385. public object NoThrowTarget(CallSite site, object self, CodeContext context) {
  386. if (self != null && self.GetType() == typeof(PythonModule)) {
  387. return ((PythonModule)self).GetAttributeNoThrow(context, _name);
  388. }
  389. return Update(site, self, context);
  390. }
  391. public override bool IsValid(PythonType type) {
  392. return true;
  393. }
  394. }
  395. class NamespaceTrackerDelegate : FastGetBase {
  396. private readonly string _name;
  397. public NamespaceTrackerDelegate(string name) {
  398. _name = name;
  399. }
  400. public object Target(CallSite site, object self, CodeContext context) {
  401. if (self != null && self.GetType() == typeof(NamespaceTracker)) {
  402. object res = NamespaceTrackerOps.GetCustomMember(context, (NamespaceTracker)self, _name);
  403. if (res != OperationFailed.Value) {
  404. return res;
  405. }
  406. throw PythonOps.AttributeErrorForMissingAttribute(self, _name);
  407. }
  408. return Update(site, self, context);
  409. }
  410. public object NoThrowTarget(CallSite site, object self, CodeContext context) {
  411. if (self != null && self.GetType() == typeof(NamespaceTracker)) {
  412. return NamespaceTrackerOps.GetCustomMember(context, (NamespaceTracker)self, _name);
  413. }
  414. return Update(site, self, context);
  415. }
  416. public object GetName(CallSite site, object self, CodeContext context) {
  417. if (self != null && self.GetType() == typeof(NamespaceTracker)) {
  418. return NamespaceTrackerOps.Get__name__(context, (NamespaceTracker)self);
  419. }
  420. return Update(site, self, context);
  421. }
  422. public object GetFile(CallSite site, object self, CodeContext context) {
  423. if (self != null && self.GetType() == typeof(NamespaceTracker)) {
  424. return NamespaceTrackerOps.Get__file__((NamespaceTracker)self);
  425. }
  426. return Update(site, self, context);
  427. }
  428. public object GetDict(CallSite site, object self, CodeContext context) {
  429. if (self != null && self.GetType() == typeof(NamespaceTracker)) {
  430. return NamespaceTrackerOps.Get__dict__(context, (NamespaceTracker)self);
  431. }
  432. return Update(site, self, context);
  433. }
  434. public override bool IsValid(PythonType type) {
  435. return true;
  436. }
  437. }
  438. private DynamicMetaObject GetForeignObject(DynamicMetaObject self) {
  439. return new DynamicMetaObject(
  440. Expression.Dynamic(
  441. _context.CompatGetMember(Name, IsNoThrow),
  442. typeof(object),
  443. self.Expression
  444. ),
  445. self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType()))
  446. );
  447. }
  448. #endregion
  449. public DynamicMetaObject/*!*/ Fallback(DynamicMetaObject/*!*/ self, DynamicMetaObject/*!*/ codeContext) {
  450. // Python always provides an extra arg to GetMember to flow the context.
  451. return FallbackWorker(_context, self, codeContext, Name, _options, this, null);
  452. }
  453. public DynamicMetaObject/*!*/ Fallback(DynamicMetaObject/*!*/ self, DynamicMetaObject/*!*/ codeContext, DynamicMetaObject errorSuggestion) {
  454. // Python always provides an extra arg to GetMember to flow the context.
  455. return FallbackWorker(_context, self, codeContext, Name, _options, this, errorSuggestion);
  456. }
  457. internal static DynamicMetaObject FallbackWorker(PythonContext context, DynamicMetaObject/*!*/ self, DynamicMetaObject/*!*/ codeContext, string name, GetMemberOptions options, DynamicMetaObjectBinder action, DynamicMetaObject errorSuggestion) {
  458. if (self.NeedsDeferral()) {
  459. return action.Defer(self);
  460. }
  461. PythonOverloadResolverFactory resolverFactory = new PythonOverloadResolverFactory(context.Binder, codeContext.Expression);
  462. PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "FallbackGet");
  463. bool isNoThrow = ((options & GetMemberOptions.IsNoThrow) != 0) ? true : false;
  464. Type limitType = self.GetLimitType();
  465. if (limitType == typeof(DynamicNull) || PythonBinder.IsPythonType(limitType)) {
  466. // look up in the PythonType so that we can
  467. // get our custom method names (e.g. string.startswith)
  468. PythonType argType = DynamicHelpers.GetPythonTypeFromType(limitType);
  469. // if the name is defined in the CLS context but not the normal context then
  470. // we will hide it.
  471. if (argType.IsHiddenMember(name)) {
  472. DynamicMetaObject baseRes = PythonContext.GetPythonContext(action).Binder.GetMember(
  473. name,
  474. self,
  475. resolverFactory,
  476. isNoThrow,
  477. errorSuggestion
  478. );
  479. Expression failure = GetFailureExpression(limitType, self, name, isNoThrow, action);
  480. return BindingHelpers.FilterShowCls(codeContext, action, baseRes, failure);
  481. }
  482. }
  483. if (self.GetLimitType() == typeof(OldInstance)) {
  484. if ((options & GetMemberOptions.IsNoThrow) != 0) {
  485. return new DynamicMetaObject(
  486. Ast.Field(
  487. null,
  488. typeof(OperationFailed).GetField("Value")
  489. ),
  490. self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance)))
  491. );
  492. } else {
  493. return new DynamicMetaObject(
  494. Ast.Throw(
  495. Ast.Call(
  496. typeof(PythonOps).GetMethod("AttributeError"),
  497. AstUtils.Constant("{0} instance has no attribute '{1}'"),
  498. Ast.NewArrayInit(
  499. typeof(object),
  500. AstUtils.Constant(((OldInstance)self.Value)._class._name),
  501. AstUtils.Constant(name)
  502. )
  503. )
  504. ),
  505. self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(OldInstance)))
  506. );
  507. }
  508. }
  509. var res = PythonContext.GetPythonContext(action).Binder.GetMember(name, self, resolverFactory, isNoThrow, errorSuggestion);
  510. // Default binder can return something typed to boolean or int.
  511. // If that happens, we need to apply Python's boxing rules.
  512. if (res.Expression.Type.IsValueType) {
  513. res = new DynamicMetaObject(
  514. AstUtils.Convert(res.Expression, typeof(object)),
  515. res.Restrictions
  516. );
  517. }
  518. return res;
  519. }
  520. private static Expression/*!*/ GetFailureExpression(Type/*!*/ limitType, DynamicMetaObject self, string name, bool isNoThrow, DynamicMetaObjectBinder action) {
  521. return isNoThrow ?
  522. Ast.Field(null, typeof(OperationFailed).GetField("Value")) :
  523. DefaultBinder.MakeError(
  524. PythonContext.GetPythonContext(action).Binder.MakeMissingMemberError(
  525. limitType,
  526. self,
  527. name
  528. ),
  529. typeof(object)
  530. ).Expression;
  531. }
  532. public string Name {
  533. get {
  534. return _name;
  535. }
  536. }
  537. public PythonContext/*!*/ Context {
  538. get {
  539. return _context;
  540. }
  541. }
  542. public bool IsNoThrow {
  543. get {
  544. return (_options & GetMemberOptions.IsNoThrow) != 0;
  545. }
  546. }
  547. public override int GetHashCode() {
  548. return _name.GetHashCode() ^ _context.Binder.GetHashCode() ^ ((int)_options);
  549. }
  550. public override bool Equals(object obj) {
  551. PythonGetMemberBinder ob = obj as PythonGetMemberBinder;
  552. if (ob == null) {
  553. return false;
  554. }
  555. return ob._context.Binder == _context.Binder &&
  556. ob._options == _options &&
  557. ob._name == _name;
  558. }
  559. public override string ToString() {
  560. return String.Format("Python GetMember {0} IsNoThrow: {1}", Name, _options);
  561. }
  562. #region IExpressionSerializable Members
  563. public Expression CreateExpression() {
  564. return Ast.Call(
  565. typeof(PythonOps).GetMethod("MakeGetAction"),
  566. BindingHelpers.CreateBinderStateExpression(),
  567. AstUtils.Constant(Name),
  568. AstUtils.Constant(IsNoThrow)
  569. );
  570. }
  571. #endregion
  572. }
  573. class CompatibilityGetMember : GetMemberBinder, IPythonSite, IInvokeOnGetBinder {
  574. private readonly PythonContext/*!*/ _context;
  575. private readonly bool _isNoThrow;
  576. public CompatibilityGetMember(PythonContext/*!*/ context, string/*!*/ name)
  577. : base(name, false) {
  578. _context = context;
  579. }
  580. public CompatibilityGetMember(PythonContext/*!*/ context, string/*!*/ name, bool isNoThrow)
  581. : base(name, false) {
  582. _context = context;
  583. _isNoThrow = isNoThrow;
  584. }
  585. public override DynamicMetaObject FallbackGetMember(DynamicMetaObject self, DynamicMetaObject errorSuggestion) {
  586. #if !SILVERLIGHT
  587. DynamicMetaObject com;
  588. if (Microsoft.Scripting.ComInterop.ComBinder.TryBindGetMember(this, self, out com, true)) {
  589. return com;
  590. }
  591. #endif
  592. return PythonGetMemberBinder.FallbackWorker(_context, self, PythonContext.GetCodeContextMOCls(this), Name, _isNoThrow ? GetMemberOptions.IsNoThrow : GetMemberOptions.None, this, errorSuggestion);
  593. }
  594. #region IPythonSite Members
  595. public PythonContext Context {
  596. get { return _context; }
  597. }
  598. #endregion
  599. public override int GetHashCode() {
  600. return base.GetHashCode() ^ _context.Binder.GetHashCode();
  601. }
  602. public override bool Equals(object obj) {
  603. CompatibilityGetMember ob = obj as CompatibilityGetMember;
  604. if (ob == null) {
  605. return false;
  606. }
  607. return ob._context.Binder == _context.Binder &&
  608. base.Equals(obj);
  609. }
  610. #region IInvokeOnGetBinder Members
  611. public bool InvokeOnGet {
  612. get { return false; }
  613. }
  614. #endregion
  615. }
  616. [Flags]
  617. enum GetMemberOptions {
  618. None,
  619. IsNoThrow = 0x01,
  620. IsCaseInsensitive = 0x02
  621. }
  622. }