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

/Microsoft.Scripting/Runtime/Scope.cs

https://bitbucket.org/stefanrusek/xronos
C# | 317 lines | 161 code | 42 blank | 114 comment | 18 complexity | 5ca19c819665192c4ec5f8186dfd2f2d 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 CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. #if CODEPLEX_40
  22. using System.Linq.Expressions;
  23. #else
  24. using Microsoft.Linq.Expressions;
  25. #endif
  26. using Microsoft.Scripting.Utils;
  27. using System.Threading;
  28. namespace Microsoft.Scripting.Runtime {
  29. /// <summary>
  30. /// Represents a context of execution. A context of execution has a set of variables
  31. /// associated with it (its dictionary) and a parent context.
  32. ///
  33. /// When looking up a name from a context first the local context is searched. If the
  34. /// name is not found there the name lookup will be done against the parent context.
  35. ///
  36. /// Scopes, like IAttrbibuteCollections, support both being indexed by SymbolId for fast
  37. /// access as well as being indexed by object. The preferred access is via SymbolId and
  38. /// object access is provided for languages which require additional semantics. All
  39. /// features supported for feature IDs are also supported for objects (e.g. context-sentsitivity
  40. /// and attributes) but the object API does not contain all the same sets of overloads provided
  41. /// for convenience.
  42. ///
  43. /// TODO: Thread safety
  44. /// </summary>
  45. public class Scope {
  46. private ScopeExtension[] _extensions; // resizable
  47. private IAttributesCollection _dict;
  48. // TODO: remove
  49. private readonly Scope _parent;
  50. private bool _isVisible;
  51. /// <summary>
  52. /// Creates a new top-level scope with a new empty dictionary. The scope
  53. /// is marked as being visible.
  54. /// </summary>
  55. public Scope()
  56. : this(null, null) {
  57. }
  58. /// <summary>
  59. /// Creates a new top-level Scope with the provided dictionary
  60. /// </summary>
  61. public Scope(IAttributesCollection dictionary)
  62. : this(null, dictionary) {
  63. }
  64. /// <summary>
  65. /// Creates a new Scope with the provided parent and dictionary.
  66. /// </summary>
  67. public Scope(Scope parent, IAttributesCollection dictionary)
  68. : this(parent, dictionary, true) {
  69. }
  70. /// <summary>
  71. /// Creates a new Scope with the provided parent, dictionary and visibility.
  72. /// </summary>
  73. public Scope(Scope parent, IAttributesCollection dictionary, bool isVisible) {
  74. _parent = parent;
  75. _dict = dictionary ?? new SymbolDictionary();
  76. _isVisible = isVisible;
  77. _extensions = ScopeExtension.EmptyArray;
  78. }
  79. public ScopeExtension GetExtension(ContextId languageContextId) {
  80. return (languageContextId.Id < _extensions.Length) ? _extensions[languageContextId.Id] : null;
  81. }
  82. public ScopeExtension SetExtension(ContextId languageContextId, ScopeExtension extension) {
  83. ContractUtils.RequiresNotNull(extension, "extension");
  84. if (languageContextId.Id >= _extensions.Length) {
  85. Array.Resize(ref _extensions, languageContextId.Id + 1);
  86. }
  87. ScopeExtension original = Interlocked.CompareExchange(ref _extensions[languageContextId.Id], extension, null);
  88. return original ?? extension;
  89. }
  90. /// <summary>
  91. /// Gets the parent of this Scope or null if the Scope has no parent.
  92. /// </summary>
  93. public Scope Parent {
  94. get {
  95. return _parent;
  96. }
  97. }
  98. /// <summary>
  99. /// Gets if the context is visible at this scope. Visibility is a per-language feature that enables
  100. /// languages to include members in the Scope chain but hide them when directly exposed to the user.
  101. /// </summary>
  102. public bool IsVisible {
  103. get {
  104. return _isVisible;
  105. }
  106. }
  107. /// <summary>
  108. /// Returns the list of keys which are available to all languages. Keys marked with the
  109. /// DontEnumerate flag will not be returned.
  110. /// </summary>
  111. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] // TODO: fix
  112. public IEnumerable<SymbolId> Keys {
  113. get {
  114. foreach (object name in _dict.Keys) {
  115. string strName = name as string;
  116. if (strName == null) continue;
  117. yield return SymbolTable.StringToId(strName);
  118. }
  119. }
  120. }
  121. /// <summary>
  122. /// Returns the list of Keys and Items which are available to all languages. Keys marked
  123. /// with the DontEnumerate flag will not be returned.
  124. /// </summary>
  125. public IEnumerable<KeyValuePair<SymbolId, object>> Items {
  126. get {
  127. foreach (KeyValuePair<SymbolId, object> kvp in _dict.SymbolAttributes) {
  128. yield return kvp;
  129. }
  130. }
  131. }
  132. /// <summary>
  133. /// Returns the list of Keys available to all languages in addition to those keys
  134. /// which are only available to the provided LanguageContext.
  135. ///
  136. /// Keys marked with the DontEnumerate flag will not be returned.
  137. /// </summary>
  138. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] // TODO: fix
  139. public IEnumerable<SymbolId> GetKeys(LanguageContext context) {
  140. foreach (SymbolId si in _dict.SymbolAttributes.Keys) {
  141. yield return si;
  142. }
  143. }
  144. /// <summary>
  145. /// Trys to lookup the provided name in the current scope. Search includes
  146. /// names that are only visible to the provided LanguageContext.
  147. /// </summary>
  148. public bool TryGetName(SymbolId name, out object value) {
  149. if (_dict.TryGetValue(name, out value)) return true;
  150. value = null;
  151. return false;
  152. }
  153. /// <summary>
  154. /// Attempts to lookup the provided name in this scope or any outer scope.
  155. /// </summary>
  156. public bool TryLookupName(SymbolId name, out object value) {
  157. Scope curScope = this;
  158. do {
  159. if (curScope == this || curScope.IsVisible) {
  160. if (curScope.TryGetName(name, out value)) {
  161. return true;
  162. }
  163. }
  164. curScope = curScope.Parent;
  165. } while (curScope != null);
  166. value = null;
  167. return false;
  168. }
  169. /// <summary>
  170. /// Attempts to lookup the provided name in this scope or any outer scope.
  171. /// If the name is not defined the language defined MissingName exception is thrown.
  172. /// </summary>
  173. public object LookupName(LanguageContext context, SymbolId name) {
  174. object res;
  175. if (!TryLookupName(name, out res)) {
  176. throw context.MissingName(name);
  177. }
  178. return res;
  179. }
  180. /// <summary>
  181. /// Sets the name to the specified value for the current context.
  182. /// </summary>
  183. /// <exception cref="MemberAccessException">The name has already been published and marked as ReadOnly</exception>
  184. public void SetName(SymbolId name, object value) {
  185. _dict[name] = value;
  186. }
  187. /// <summary>
  188. /// Removes all members from the dictionary and any context-sensitive dictionaries.
  189. /// </summary>
  190. public void Clear() {
  191. List<object> ids = new List<object>(_dict.Keys);
  192. foreach (object name in ids) {
  193. _dict.RemoveObjectKey(name);
  194. }
  195. }
  196. /// <summary>
  197. /// Determines if this context or any outer scope contains the defined name that
  198. /// is available from the provided LanguageContext.
  199. /// </summary>
  200. public bool ContainsName(SymbolId name) {
  201. object tmp;
  202. return TryLookupName(name, out tmp);
  203. }
  204. /// <summary>
  205. /// Attemps to remove the provided name from this scope removing names visible
  206. /// to both the current context and all contexts.
  207. /// </summary>
  208. public bool TryRemoveName(SymbolId name) {
  209. bool fRemoved = false;
  210. // TODO: Ideally, we could do this without having to do two lookups.
  211. object removedObject;
  212. if (_dict.TryGetValue(name, out removedObject) && removedObject != Uninitialized.Instance) {
  213. fRemoved = _dict.Remove(name) || fRemoved;
  214. }
  215. return fRemoved;
  216. }
  217. // Emitted by TupleSlotFactory
  218. /// <summary>
  219. /// Gets the outer-most scope associated with this scope.
  220. /// </summary>
  221. public Scope ModuleScope {
  222. get {
  223. Scope cur = this;
  224. while (cur.Parent != null) cur = cur.Parent;
  225. return cur;
  226. }
  227. }
  228. /// <summary>
  229. /// Default scope dictionary
  230. /// </summary>
  231. public IAttributesCollection Dict {
  232. get {
  233. return _dict;
  234. }
  235. }
  236. #region Object key access
  237. /// <summary>
  238. /// Attemps to remove the provided object name from this scope removing names visible
  239. /// to both the current context and all contexts.
  240. /// </summary>
  241. public bool TryRemoveObjectName(object name) {
  242. return _dict.RemoveObjectKey(name);
  243. }
  244. public bool TryGetObjectName(object name, out object value) {
  245. if (_dict.TryGetObjectValue(name, out value)) return true;
  246. value = null;
  247. return false;
  248. }
  249. /// <summary>
  250. /// Sets the name to the specified value for the current context.
  251. ///
  252. /// The name is an arbitrary object.
  253. /// </summary>
  254. public void SetObjectName(object name, object value) {
  255. _dict.AddObjectKey(name, value);
  256. }
  257. public IEnumerable<object> GetAllKeys() {
  258. foreach (object key in _dict.Keys) {
  259. yield return key;
  260. }
  261. }
  262. /// <summary>
  263. /// Returns the list of Keys and Values available to all languages in addition to those
  264. /// keys which are only available to the provided LanguageContext.
  265. ///
  266. /// Keys marked with DontEnumerate flag will not be returned.
  267. /// </summary>
  268. public IEnumerable<KeyValuePair<object, object>> GetAllItems() {
  269. foreach (KeyValuePair<object, object> kvp in _dict) {
  270. yield return kvp;
  271. }
  272. }
  273. #endregion
  274. }
  275. }