aspclassic-core/AspClassic.Scripting/Runtime/DlrConfiguration.cs
Jelle Luteijn 484dbfc9d9 progress
2022-05-15 11:19:49 +02:00

220 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using AspClassic.Scripting.Utils;
namespace AspClassic.Scripting.Runtime;
public sealed class DlrConfiguration
{
private bool _frozen;
private readonly bool _debugMode;
private readonly bool _privateBinding;
private readonly IDictionary<string, object> _options;
public static readonly StringComparer FileExtensionComparer = StringComparer.OrdinalIgnoreCase;
public static readonly StringComparer LanguageNameComparer = StringComparer.OrdinalIgnoreCase;
public static readonly StringComparer OptionNameComparer = StringComparer.Ordinal;
private readonly Dictionary<string, LanguageConfiguration> _languageNames;
private readonly Dictionary<string, LanguageConfiguration> _languageExtensions;
private readonly Dictionary<AssemblyQualifiedTypeName, LanguageConfiguration> _languageConfigurations;
private readonly Dictionary<Type, LanguageConfiguration> _loadedProviderTypes;
public bool DebugMode => _debugMode;
public bool PrivateBinding => _privateBinding;
internal IDictionary<string, object> Options => _options;
internal IDictionary<AssemblyQualifiedTypeName, LanguageConfiguration> Languages => _languageConfigurations;
public DlrConfiguration(bool debugMode, bool privateBinding, IDictionary<string, object> options)
{
ContractUtils.RequiresNotNull(options, "options");
_debugMode = debugMode;
_privateBinding = privateBinding;
_options = options;
_languageNames = new Dictionary<string, LanguageConfiguration>(LanguageNameComparer);
_languageExtensions = new Dictionary<string, LanguageConfiguration>(FileExtensionComparer);
_languageConfigurations = new Dictionary<AssemblyQualifiedTypeName, LanguageConfiguration>();
_loadedProviderTypes = new Dictionary<Type, LanguageConfiguration>();
}
public void AddLanguage(string languageTypeName, string displayName, IList<string> names, IList<string> fileExtensions, IDictionary<string, object> options)
{
AddLanguage(languageTypeName, displayName, names, fileExtensions, options, null);
}
internal void AddLanguage(string languageTypeName, string displayName, IList<string> names, IList<string> fileExtensions, IDictionary<string, object> options, string paramName)
{
ContractUtils.Requires(!_frozen, "Configuration cannot be modified once the runtime is initialized");
ContractUtils.Requires(names.TrueForAll((string id) => !string.IsNullOrEmpty(id) && !_languageNames.ContainsKey(id)), paramName ?? "names", "Language name should not be null, empty or duplicated between languages");
ContractUtils.Requires(fileExtensions.TrueForAll((string ext) => !string.IsNullOrEmpty(ext) && !_languageExtensions.ContainsKey(ext)), paramName ?? "fileExtensions", "File extension should not be null, empty or duplicated between languages");
ContractUtils.RequiresNotNull(displayName, paramName ?? "displayName");
if (string.IsNullOrEmpty(displayName))
{
ContractUtils.Requires(names.Count > 0, paramName ?? "displayName", "Must have a non-empty display name or a a non-empty list of language names");
displayName = names[0];
}
AssemblyQualifiedTypeName assemblyQualifiedTypeName = AssemblyQualifiedTypeName.ParseArgument(languageTypeName, paramName ?? "languageTypeName");
if (_languageConfigurations.ContainsKey(assemblyQualifiedTypeName))
{
throw new ArgumentException($"Duplicate language with type name '{assemblyQualifiedTypeName}'", "languageTypeName");
}
Dictionary<string, object> dictionary = new Dictionary<string, object>(_options);
foreach (KeyValuePair<string, object> option in options)
{
dictionary[option.Key] = option.Value;
}
LanguageConfiguration value = new LanguageConfiguration(assemblyQualifiedTypeName, displayName, dictionary);
_languageConfigurations.Add(assemblyQualifiedTypeName, value);
foreach (string name in names)
{
_languageNames[name] = value;
}
foreach (string fileExtension in fileExtensions)
{
_languageExtensions[NormalizeExtension(fileExtension)] = value;
}
}
internal static string NormalizeExtension(string extension)
{
if (extension[0] != '.')
{
return "." + extension;
}
return extension;
}
internal void Freeze()
{
_frozen = true;
}
internal bool TryLoadLanguage(ScriptDomainManager manager, AssemblyQualifiedTypeName providerName, out LanguageContext language)
{
if (_languageConfigurations.TryGetValue(providerName, out var value))
{
language = LoadLanguageContext(manager, value);
return true;
}
language = null;
return false;
}
internal bool TryLoadLanguage(ScriptDomainManager manager, string str, bool isExtension, out LanguageContext language)
{
Dictionary<string, LanguageConfiguration> dictionary = (isExtension ? _languageExtensions : _languageNames);
if (dictionary.TryGetValue(str, out var value))
{
language = LoadLanguageContext(manager, value);
return true;
}
language = null;
return false;
}
private LanguageContext LoadLanguageContext(ScriptDomainManager manager, LanguageConfiguration config)
{
bool alreadyLoaded;
LanguageContext languageContext = config.LoadLanguageContext(manager, out alreadyLoaded);
if (!alreadyLoaded)
{
lock (_loadedProviderTypes)
{
Type type = languageContext.GetType();
if (_loadedProviderTypes.TryGetValue(type, out var value))
{
throw new InvalidOperationException($"Language implemented by type '{config.ProviderName}' has already been loaded using name '{value.ProviderName}'");
}
_loadedProviderTypes.Add(type, config);
return languageContext;
}
}
return languageContext;
}
public string[] GetLanguageNames(LanguageContext context)
{
ContractUtils.RequiresNotNull(context, "context");
List<string> list = new List<string>();
foreach (KeyValuePair<string, LanguageConfiguration> languageName in _languageNames)
{
if (languageName.Value.LanguageContext == context)
{
list.Add(languageName.Key);
}
}
return list.ToArray();
}
internal string[] GetLanguageNames(LanguageConfiguration config)
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, LanguageConfiguration> languageName in _languageNames)
{
if (languageName.Value == config)
{
list.Add(languageName.Key);
}
}
return list.ToArray();
}
public string[] GetLanguageNames()
{
return ArrayUtils.MakeArray(_languageNames.Keys);
}
public string[] GetFileExtensions(LanguageContext context)
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, LanguageConfiguration> languageExtension in _languageExtensions)
{
if (languageExtension.Value.LanguageContext == context)
{
list.Add(languageExtension.Key);
}
}
return list.ToArray();
}
internal string[] GetFileExtensions(LanguageConfiguration config)
{
List<string> list = new List<string>();
foreach (KeyValuePair<string, LanguageConfiguration> languageExtension in _languageExtensions)
{
if (languageExtension.Value == config)
{
list.Add(languageExtension.Key);
}
}
return list.ToArray();
}
public string[] GetFileExtensions()
{
return ArrayUtils.MakeArray(_languageExtensions.Keys);
}
internal LanguageConfiguration GetLanguageConfig(LanguageContext context)
{
foreach (LanguageConfiguration value in _languageConfigurations.Values)
{
if (value.LanguageContext == context)
{
return value;
}
}
return null;
}
}