/* * Copyright © 2011, Petro Protsyk, Denys Vuika * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if SILVERLIGHT || PocketPC using DefaultAssemblyManager = Scripting.SSharp.Runtime.BaseAssemblyManager; #else using DefaultAssemblyManager = Scripting.SSharp.Runtime.AssemblyManager; #endif using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Reflection; using System.Threading; using System.Xml.Serialization; using Scripting.SSharp.Runtime.Promotion; using Scripting.SSharp.Runtime.Configuration; using Scripting.SSharp.Runtime.Operators; using Scripting.SSharp.Diagnostics; namespace Scripting.SSharp.Runtime { /// /// Run-time configuration manager for Script.net /// public static class RuntimeHost { #region Fields & Properties private static ScriptConfiguration _configuration; private static Script _initializationScript; /// /// Settings section /// private static readonly Dictionary SettingsItems = new Dictionary(); /// /// Operators /// private static readonly Dictionary BinOperators = new Dictionary(); /// /// Operators /// private static readonly Dictionary UnaryOperators = new Dictionary(); /// /// Object used to synchronize during multi-threaded execution /// private static readonly object SyncRoot = new object(); public static bool IsInitialized { get; private set; } [Promote(false)] public static IScopeFactory ScopeFactory { get; private set; } public static IObjectBinding Binder { get; set; } [Promote(false)] public static IAssemblyManager AssemblyManager { get; set; } /// /// Activator which used to activate instances /// public static IObjectActivator Activator { get; set; } private static readonly Dictionary Handlers = new Dictionary(); /// /// Should be returned by GetVariableInternal if item with given /// name not found in the scope hierarchy /// public static object NoVariable = new object(); public static object NullValue = new object(); internal static Parser.FastGrammar.LRParser Parser { get; private set; } #endregion #region Construction & Initialization /// /// Load default configuration from RuntimeConfig.xml /// [Promote(false)] public static void Initialize() { #if PocketPC || SILVERLIGHT Initialize(DefaultConfig); #else Initialize(DefaultConfig); //Initialize(Configurations.CreateDefault()); #endif } [Promote(false)] public static void Initialize(Stream configuration) { Initialize(LoadConfiguration(configuration)); } /// /// Loads given configuration /// /// [Promote(false)] public static void Initialize(ScriptConfiguration configuration) { if (IsInitialized) return; if (Parser == null) { Parser = new Parser.FastGrammar.LRParser(); } Lock(); try { _configuration = configuration; if (Binder == null) Binder = new DefaultObjectBinding(); if (Activator == null) Activator = new ObjectActivator(); InitializeSettingItems(); RegisterOperators(); if (ScopeFactory == null) ScopeFactory = Activator.CreateInstance(GetNativeType(GetSettingsItem(ConfigSchema.ScopeFactoryAttribute))) as IScopeFactory; RegisterScopes(); if (AssemblyManager == null) AssemblyManager = new DefaultAssemblyManager(); OnInitializingTypes(AssemblyManager); AssemblyManager.Initialize(_configuration); if (!string.IsNullOrEmpty(_configuration.Initialization)) _initializationScript = Script.Compile(_configuration.Initialization); RegisterOperatorHandler("+=", new EventOperatorHandler(true)); RegisterOperatorHandler("-=", new EventOperatorHandler(false)); SSharp.Parser.Ast.ScriptExpr.HandleOperator += HandleOperator; } finally { IsInitialized = true; UnLock(); } } private static void RegisterOperators() { foreach (var definition in _configuration.Operators) { var oper = (IOperator)Activator.CreateInstance(GetNativeType(definition.Type)); if (oper.Unary) UnaryOperators.Add(oper.Name, oper); else BinOperators.Add(oper.Name, oper); } } private static void HandleOperator(object sender, HandleOperatorArgs e) { IOperatorHandler handler; if (Handlers.TryGetValue(e.Symbol, out handler)) { e.Result = handler.Process(e); } } private static void RegisterScopes() { //NOTE: Default values //ScopeFactory.RegisterType(ScopeTypes.Default, typeof(ScriptScope)); //ScopeFactory.RegisterType(ScopeTypes.Contract, typeof(ScriptContractScope)); //ScopeFactory.RegisterType(ScopeTypes.Using, typeof(ScriptUsingScope)); foreach (ScopeDefinition definition in _configuration.Scopes) { ScopeFactory.RegisterType(definition.Id, (IScopeActivator)Activator.CreateInstance(GetNativeType(definition.Type))); } } /// /// Clears all information in the RuntimeHost /// [Promote(false)] public static void CleanUp() { Lock(); try { SSharp.Parser.Ast.ScriptExpr.HandleOperator -= HandleOperator; Handlers.Clear(); initializingTypes.Clear(); Binder = null; Activator = null; ScopeFactory = null; if (AssemblyManager != null) { AssemblyManager.Dispose(); AssemblyManager = null; } SettingsItems.Clear(); BinOperators.Clear(); UnaryOperators.Clear(); _initializationScript = null; _configuration = new ScriptConfiguration(); } finally { IsInitialized = false; UnLock(); } } #endregion #region Methods /// /// Loads language configuration from stream /// /// private static ScriptConfiguration LoadConfiguration(Stream configStream) { var configurationSerializer = new XmlSerializer(typeof(ScriptConfiguration)); var configuration = configurationSerializer.Deserialize(configStream) as ScriptConfiguration; if (configuration == null) throw new ScriptRuntimeException(Strings.WrongConfigurationError); return configuration; } #endregion #region Loading private static void InitializeSettingItems() { foreach (SettingXml item in _configuration.SettingXml) { object rez = item.Value; if (!string.IsNullOrEmpty(item.Converter)) rez = GetItemValue(item.Value, item.Converter); SettingsItems.Add(item.Name, rez); } } private static object GetItemValue(string value, string converter) { Type converterType = GetNativeType(converter); #if PocketPC || SILVERLIGHT try { return Convert.ChangeType(value, converterType, System.Globalization.CultureInfo.InvariantCulture); } catch { System.Diagnostics.Debug.WriteLine("Failed to convert string to type: " + converterType.ToString()); } #else var converterObject = Activator.CreateInstance(converterType) as TypeConverter; if (converterObject != null && converterObject.CanConvertFrom(typeof(string))) { return converterObject.ConvertFrom(value); } #endif return value; } #endregion #region Public methods /// /// Returns setting item specified in run-time config file /// /// /// public static object GetSettingsItem(string id) { object result; if (SettingsItems.TryGetValue(id, out result)) return result; return null; } public static void SetSettingItem(string id, object value) { Lock(); try { if (SettingsItems.ContainsKey(id)) { SettingsItems[id] = value; } else { SettingsItems.Add(id, value); } } finally { UnLock(); } } /// /// Returns setting item specified in run-time config file /// /// /// public static T GetSettingsItem(string id) { object result = GetSettingsItem(id); return result == null ? default(T) : (T)result; } [Promote(false)] public static IOperator GetBinaryOperator(string id) { IOperator oper; if (BinOperators.TryGetValue(id, out oper)) return oper; throw new NotSupportedException(string.Format("Given operator {0} is not found", id)); } [Promote(false)] public static IOperator GetUnaryOperator(string id) { IOperator oper; if (UnaryOperators.TryGetValue(id, out oper)) return oper; throw new NotSupportedException(string.Format("Given operator {0} is not found", id)); } [Promote(false)] public static void InitializeScript(IScriptContext context) { if (_initializationScript == null) return; Lock(); _initializationScript.Context = context; _initializationScript.Execute(); _initializationScript.Context = null; UnLock(); } internal static Type GetNativeType(string name) { return Type.GetType(name); } public static Type GetType(string name) { return AssemblyManager.GetType(name); } public static bool HasType(string name) { return AssemblyManager.HasType(name); } [Promote(false)] public static void AddType(string alias, Type type) { Requires.NotNullOrEmpty(alias, alias); Requires.NotNull(type, "type"); AssemblyManager.AddType(alias, type); } [Promote(false)] public static void AddType(string alias) { Requires.NotNullOrEmpty(alias, "alias"); AssemblyManager.AddType(alias, typeof(T)); } [Promote(false)] public static void RegisterOperatorHandler(string operatorSymbol, IOperatorHandler handler) { if (!Handlers.ContainsKey(operatorSymbol)) Handlers.Add(operatorSymbol, handler); else Handlers[operatorSymbol] = handler; } /// /// Lock's runtime host for threading execution /// public static void Lock() { Monitor.Enter(SyncRoot); } /// /// Unlock's thread /// public static void UnLock() { Monitor.Exit(SyncRoot); } /// /// This event is raised before AssemblyManager starts creating type system. /// It should be used to subscribe on AssemblyManager's events in order to cancel /// loading some assemblies and adding particular types /// public static event EventHandler InitializingTypes { add { initializingTypes.Add(value); } remove { initializingTypes.Remove(value); } } private static readonly List> initializingTypes = new List>(); private static void OnInitializingTypes(object sender) { foreach (var handler in initializingTypes) handler.Invoke(sender, EventArgs.Empty); } #endregion #region Config public static Stream DefaultConfig { get { var configStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("SSharp.Net.RuntimeConfig.xml"); configStream.Seek(0, SeekOrigin.Begin); return configStream; } } #endregion } }