PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Tools/IronStudio/IronPythonToolsCore/PyAnalysis/Values/LazyDotNetDict.cs

http://github.com/IronLanguages/main
C# | 289 lines | 220 code | 45 blank | 24 comment | 40 complexity | ffd4dcfd0255c11df9f16d12429101df 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. * ironpy@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. using System;
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using IronPython.Runtime;
  19. using IronPython.Runtime.Operations;
  20. using IronPython.Runtime.Types;
  21. using Microsoft.Scripting.Actions;
  22. using Microsoft.Scripting.Runtime;
  23. namespace Microsoft.PyAnalysis.Values {
  24. /// <summary>
  25. /// lazily creates nested namespaces and types from a .NET namespace. This
  26. /// just uses dir to reflect over the members and returns more Namespace objects
  27. /// which correspond with the appropriate member type.
  28. /// </summary>
  29. internal class LazyDotNetDict : IDictionary<string, ISet<Namespace>> {
  30. private readonly Dictionary<string, ISet<Namespace>> _variables;
  31. private readonly object[] _objects;
  32. private readonly ProjectState _projectState;
  33. private readonly bool _showClr;
  34. private Dictionary<object, IList<string>> _nonClrAttributes;
  35. private bool _gotAll;
  36. public LazyDotNetDict(object obj, ProjectState projectState, bool showClr)
  37. : this(new[] { obj }, projectState, showClr) {
  38. }
  39. public LazyDotNetDict(IEnumerable<object> objects, ProjectState projectState, bool showClr) {
  40. _objects = objects.ToArray();
  41. _variables = new Dictionary<string, ISet<Namespace>>();
  42. _projectState = projectState;
  43. _showClr = showClr;
  44. }
  45. public ISet<Namespace> GetValue(string index, ISet<Namespace> defaultValue) {
  46. return GetClr(index, _showClr, defaultValue);
  47. }
  48. public bool IsVisible(object module, string index, bool showClr) {
  49. if (showClr) {
  50. return true;
  51. }
  52. if (_nonClrAttributes == null) {
  53. _nonClrAttributes = new Dictionary<object, IList<string>>();
  54. }
  55. IList<string> members;
  56. if (!_nonClrAttributes.TryGetValue(module, out members)) {
  57. _nonClrAttributes[module] = members = Utils.DirHelper(module, false);
  58. }
  59. return members.IndexOf(index) != -1;
  60. }
  61. private object GetOne(object module, string index, bool showClr) {
  62. if (IsVisible(module, index, showClr)) {
  63. PythonType pyType = (module as PythonType);
  64. if (pyType != null) {
  65. foreach (var baseType in pyType.mro()) {
  66. PythonType curType = (baseType as PythonType);
  67. if (curType != null) {
  68. IDictionary<object, object> dict = new DictProxy(curType);
  69. object bresult;
  70. if (dict.TryGetValue(index, out bresult)) {
  71. return bresult;
  72. }
  73. }
  74. }
  75. }
  76. var tracker = module as NamespaceTracker;
  77. if (tracker != null) {
  78. object value = NamespaceTrackerOps.GetCustomMember(_projectState.CodeContext, tracker, index);
  79. if (value != OperationFailed.Value) {
  80. return value;
  81. } else {
  82. return this;
  83. }
  84. }
  85. object result;
  86. if (_projectState.TryGetMember(module, index, showClr, out result)) {
  87. return result;
  88. }
  89. }
  90. return this; // sentinel indicating failure
  91. }
  92. internal ISet<Namespace> GetClr(string index, bool showClr, ISet<Namespace> defaultValue) {
  93. ISet<Namespace> result;
  94. if (_variables.TryGetValue(index, out result)) {
  95. return result ?? defaultValue;
  96. }
  97. var attrs = new List<object>();
  98. foreach (var module in _objects) {
  99. try {
  100. var attr = GetOne(module, index, showClr);
  101. if (attr != this) {
  102. attrs.Add(attr);
  103. }
  104. } catch {
  105. // TODO: Remove when Python bug is fixed
  106. }
  107. }
  108. if (attrs.Count > 0) {
  109. var ns = _projectState.GetNamespaceFromObjects(attrs);
  110. result = _variables[index] = ns.SelfSet;
  111. return result;
  112. } else {
  113. _variables[index] = null;
  114. }
  115. return defaultValue;
  116. }
  117. public object[] Objects {
  118. get { return _objects; }
  119. }
  120. #region IDictionary<string,Namespace> Members
  121. public void Add(string key, ISet<Namespace> value) {
  122. throw new InvalidOperationException();
  123. }
  124. public bool ContainsKey(string key) {
  125. throw new NotImplementedException();
  126. }
  127. public ICollection<string> Keys {
  128. get {
  129. EnsureAll();
  130. List<string> res = new List<string>(_variables.Count);
  131. foreach (var v in _variables) {
  132. if (v.Value != null) {
  133. res.Add(v.Key);
  134. }
  135. }
  136. return res;
  137. }
  138. }
  139. private void EnsureAll() {
  140. if (!_gotAll) {
  141. HashSet<string> result = new HashSet<string>();
  142. if (_objects.Length == 1 && (_objects[0] is PythonType)) {
  143. // fast path for when we're looking up in a type, this is about twice as fast
  144. // as going through the normal code path.
  145. PythonType pyType = (PythonType)_objects[0];
  146. foreach (var baseType in pyType.mro()) {
  147. PythonType curType = (baseType as PythonType);
  148. if (curType != null) {
  149. var dict = new DictProxy(curType);
  150. var enumerator = dict.iteritems(_showClr ? _projectState.CodeContextCls : _projectState.CodeContext);
  151. while (enumerator.MoveNext()) {
  152. PythonTuple value = (PythonTuple)enumerator.Current;
  153. string key = (string)value[0];
  154. if (_variables.ContainsKey(key)) {
  155. continue;
  156. }
  157. _variables[key] = _projectState.GetNamespaceFromObjects(value[1]).SelfSet;
  158. }
  159. }
  160. }
  161. } else {
  162. foreach (var module in _objects) {
  163. foreach (var name in Utils.DirHelper(module, _showClr)) {
  164. GetClr(name, _showClr, null);
  165. }
  166. }
  167. }
  168. _gotAll = true;
  169. }
  170. }
  171. public bool Remove(string key) {
  172. throw new InvalidOperationException();
  173. }
  174. public bool TryGetValue(string key, out ISet<Namespace> value) {
  175. EnsureAll();
  176. return _variables.TryGetValue(key, out value) && value != null;
  177. }
  178. public ICollection<ISet<Namespace>> Values {
  179. get { throw new NotImplementedException(); }
  180. }
  181. public ISet<Namespace> this[string index] {
  182. get {
  183. ISet<Namespace> result = GetValue(index, null);
  184. if (result != null) {
  185. return result;
  186. }
  187. if (Keys.Contains(index)) {
  188. // work around bug where IronPython includes property methods
  189. // in types overloaded by generic arity (e.g.
  190. // System.Linq.Expressions.Expression)
  191. return EmptySet<Namespace>.Instance;
  192. }
  193. throw new KeyNotFoundException(String.Format("Key {0} not found", index));
  194. }
  195. set {
  196. _variables[index] = value;
  197. }
  198. }
  199. #endregion
  200. #region ICollection<KeyValuePair<string,ISet<Namespace>>> Members
  201. public void Add(KeyValuePair<string, ISet<Namespace>> item) {
  202. throw new InvalidOperationException();
  203. }
  204. public void Clear() {
  205. throw new InvalidOperationException();
  206. }
  207. public bool Contains(KeyValuePair<string, ISet<Namespace>> item) {
  208. throw new NotImplementedException();
  209. }
  210. public void CopyTo(KeyValuePair<string, ISet<Namespace>>[] array, int arrayIndex) {
  211. throw new NotImplementedException();
  212. }
  213. public int Count {
  214. get { return Keys.Count; }
  215. }
  216. public bool IsReadOnly {
  217. get { return true; }
  218. }
  219. public bool Remove(KeyValuePair<string, ISet<Namespace>> item) {
  220. throw new InvalidOperationException();
  221. }
  222. #endregion
  223. #region IEnumerable<KeyValuePair<string,ISet<Namespace>>> Members
  224. public IEnumerator<KeyValuePair<string, ISet<Namespace>>> GetEnumerator() {
  225. EnsureAll();
  226. foreach (var v in _variables) {
  227. if (v.Value != null) {
  228. yield return v;
  229. }
  230. }
  231. }
  232. #endregion
  233. #region IEnumerable Members
  234. IEnumerator IEnumerable.GetEnumerator() {
  235. return GetEnumerator();
  236. }
  237. #endregion
  238. public ProjectState ProjectState {
  239. get {
  240. return _projectState;
  241. }
  242. }
  243. }
  244. }