220 lines
7.2 KiB
C#
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;
|
|
}
|
|
}
|