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