PageRenderTime 17ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Runtime/Microsoft.Scripting/Runtime/Scope.cs

https://github.com/thomo13/ironruby
C# | 164 lines | 94 code | 25 blank | 45 comment | 3 complexity | 1d41539b5c7c2c45b9f2148374fafdbf MD5 | raw file
  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 dynamic = System.Object;
  19. using Microsoft.Scripting.Ast;
  20. #endif
  21. using System;
  22. using System.Collections.Generic;
  23. using Microsoft.Scripting.Utils;
  24. using System.Dynamic;
  25. namespace Microsoft.Scripting.Runtime {
  26. /// <summary>
  27. /// Represents a host-provided variables for executable code. The variables are
  28. /// typically backed by a host-provided dictionary. Languages can also associate per-language
  29. /// information with the context by using scope extensions. This can be used for tracking
  30. /// state which is used across multiple executions, for providing custom forms of
  31. /// storage (for example object keyed access), or other language specific semantics.
  32. ///
  33. /// Scope objects are thread-safe as long as their underlying storage is thread safe.
  34. ///
  35. /// Script hosts can choose to use thread safe or thread unsafe modules but must be sure
  36. /// to constrain the code they right to be single-threaded if using thread unsafe
  37. /// storage.
  38. /// </summary>
  39. public sealed class Scope : IDynamicMetaObjectProvider {
  40. private ScopeExtension[] _extensions; // resizable
  41. private readonly IDynamicMetaObjectProvider _storage;
  42. /// <summary>
  43. /// Creates a new scope with a new empty thread-safe dictionary.
  44. /// </summary>
  45. public Scope() {
  46. _extensions = ScopeExtension.EmptyArray;
  47. _storage = new ScopeStorage();
  48. }
  49. public Scope(IDictionary<string, object> dictionary) {
  50. _extensions = ScopeExtension.EmptyArray;
  51. _storage = new StringDictionaryExpando(dictionary);
  52. }
  53. /// <summary>
  54. /// Creates a new scope which is backed by an arbitrary object for it's storage.
  55. /// </summary>
  56. /// <param name="storage"></param>
  57. public Scope(IDynamicMetaObjectProvider storage) {
  58. _extensions = ScopeExtension.EmptyArray;
  59. _storage = storage;
  60. }
  61. /// <summary>
  62. /// Gets the ScopeExtension associated with the provided ContextId.
  63. /// </summary>
  64. public ScopeExtension GetExtension(ContextId languageContextId) {
  65. return (languageContextId.Id < _extensions.Length) ? _extensions[languageContextId.Id] : null;
  66. }
  67. /// <summary>
  68. /// Sets the ScopeExtension to the provided value for the given ContextId.
  69. ///
  70. /// The extension can only be set once. The returned value is either the new ScopeExtension
  71. /// if no value was previously set or the previous value.
  72. /// </summary>
  73. public ScopeExtension SetExtension(ContextId languageContextId, ScopeExtension extension) {
  74. ContractUtils.RequiresNotNull(extension, "extension");
  75. lock (_extensions) {
  76. if (languageContextId.Id >= _extensions.Length) {
  77. Array.Resize(ref _extensions, languageContextId.Id + 1);
  78. }
  79. return _extensions[languageContextId.Id] ?? (_extensions[languageContextId.Id] = extension);
  80. }
  81. }
  82. public dynamic Storage {
  83. get {
  84. return _storage;
  85. }
  86. }
  87. internal sealed class MetaScope : DynamicMetaObject {
  88. public MetaScope(Expression parameter, Scope scope)
  89. : base(parameter, BindingRestrictions.Empty, scope) {
  90. }
  91. public override DynamicMetaObject BindGetMember(GetMemberBinder binder) {
  92. return Restrict(StorageMetaObject.BindGetMember(binder));
  93. }
  94. public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
  95. return Restrict(StorageMetaObject.BindInvokeMember(binder, args));
  96. }
  97. public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
  98. return Restrict(StorageMetaObject.BindSetMember(binder, value));
  99. }
  100. public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
  101. return Restrict(StorageMetaObject.BindDeleteMember(binder));
  102. }
  103. private DynamicMetaObject Restrict(DynamicMetaObject result) {
  104. if (Expression.Type == typeof(Scope)) {
  105. // ideal binding, we add no new restrictions if we're binding against a strongly typed Scope
  106. return result;
  107. }
  108. // Un-ideal binding: we add restrictions.
  109. return new DynamicMetaObject(result.Expression, BindingRestrictions.GetTypeRestriction(Expression, typeof(Scope)).Merge(result.Restrictions));
  110. }
  111. private DynamicMetaObject StorageMetaObject {
  112. get {
  113. return DynamicMetaObject.Create(Value._storage, StorageExpression);
  114. }
  115. }
  116. private MemberExpression StorageExpression {
  117. get {
  118. return Expression.Property(
  119. Expression.Convert(Expression, typeof(Scope)),
  120. typeof(Scope).GetProperty("Storage")
  121. );
  122. }
  123. }
  124. public override IEnumerable<string> GetDynamicMemberNames() {
  125. return StorageMetaObject.GetDynamicMemberNames();
  126. }
  127. public new Scope Value {
  128. get {
  129. return (Scope)base.Value;
  130. }
  131. }
  132. }
  133. #region IDynamicMetaObjectProvider Members
  134. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  135. return new MetaScope(parameter, this);
  136. }
  137. #endregion
  138. }
  139. }