progress
This commit is contained in:
parent
16e76d6b31
commit
484dbfc9d9
529 changed files with 113694 additions and 0 deletions
33
AspClassic.Scripting/Runtime/BaseSymbolDictionary.cs
Normal file
33
AspClassic.Scripting/Runtime/BaseSymbolDictionary.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal abstract class BaseSymbolDictionary
|
||||
{
|
||||
private const int ObjectKeysId = -2;
|
||||
|
||||
private static readonly object _nullObject = new object();
|
||||
|
||||
internal static readonly SymbolId ObjectKeys = new SymbolId(-2);
|
||||
|
||||
public static object NullToObj(object o)
|
||||
{
|
||||
if (o == null)
|
||||
{
|
||||
return _nullObject;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public static object ObjToNull(object o)
|
||||
{
|
||||
if (o == _nullObject)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public static bool IsNullObject(object o)
|
||||
{
|
||||
return o == _nullObject;
|
||||
}
|
||||
}
|
78
AspClassic.Scripting/Runtime/ContextId.cs
Normal file
78
AspClassic.Scripting/Runtime/ContextId.cs
Normal file
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
[Serializable]
|
||||
public struct ContextId : IEquatable<ContextId>
|
||||
{
|
||||
private int _id;
|
||||
|
||||
private static Dictionary<object, ContextId> _contexts = new Dictionary<object, ContextId>();
|
||||
|
||||
private static int _maxId = 1;
|
||||
|
||||
public static readonly ContextId Empty = default(ContextId);
|
||||
|
||||
public int Id => _id;
|
||||
|
||||
internal ContextId(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public static ContextId RegisterContext(object identifier)
|
||||
{
|
||||
lock (_contexts)
|
||||
{
|
||||
if (_contexts.TryGetValue(identifier, out var _))
|
||||
{
|
||||
throw Error.LanguageRegistered();
|
||||
}
|
||||
ContextId result = default(ContextId);
|
||||
result._id = _maxId++;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static ContextId LookupContext(object identifier)
|
||||
{
|
||||
lock (_contexts)
|
||||
{
|
||||
if (_contexts.TryGetValue(identifier, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return Empty;
|
||||
}
|
||||
|
||||
public bool Equals(ContextId other)
|
||||
{
|
||||
return _id == other._id;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is ContextId contextId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return contextId._id == _id;
|
||||
}
|
||||
|
||||
public static bool operator ==(ContextId self, ContextId other)
|
||||
{
|
||||
return self.Equals(other);
|
||||
}
|
||||
|
||||
public static bool operator !=(ContextId self, ContextId other)
|
||||
{
|
||||
return !self.Equals(other);
|
||||
}
|
||||
}
|
220
AspClassic.Scripting/Runtime/DlrConfiguration.cs
Normal file
220
AspClassic.Scripting/Runtime/DlrConfiguration.cs
Normal file
|
@ -0,0 +1,220 @@
|
|||
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;
|
||||
}
|
||||
}
|
11
AspClassic.Scripting/Runtime/DocumentationProvider.cs
Normal file
11
AspClassic.Scripting/Runtime/DocumentationProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using AspClassic.Scripting.Hosting;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public abstract class DocumentationProvider
|
||||
{
|
||||
public abstract ICollection<MemberDoc> GetMembers(object value);
|
||||
|
||||
public abstract ICollection<OverloadDoc> GetOverloads(object value);
|
||||
}
|
514
AspClassic.Scripting/Runtime/DynamicOperations.cs
Normal file
514
AspClassic.Scripting/Runtime/DynamicOperations.cs
Normal file
|
@ -0,0 +1,514 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public sealed class DynamicOperations
|
||||
{
|
||||
private class SiteKey : IEquatable<SiteKey>
|
||||
{
|
||||
internal readonly CallSiteBinder SiteBinder;
|
||||
|
||||
private readonly Type _siteType;
|
||||
|
||||
public int HitCount;
|
||||
|
||||
public CallSite Site;
|
||||
|
||||
public SiteKey(Type siteType, CallSiteBinder siteBinder)
|
||||
{
|
||||
SiteBinder = siteBinder;
|
||||
_siteType = siteType;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as SiteKey);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return SiteBinder.GetHashCode() ^ _siteType.GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(SiteKey other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (other.SiteBinder.Equals(SiteBinder))
|
||||
{
|
||||
return other._siteType == _siteType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private const int CleanupThreshold = 20;
|
||||
|
||||
private const int RemoveThreshold = 2;
|
||||
|
||||
private const int StopCleanupThreshold = 10;
|
||||
|
||||
private const int ClearThreshold = 50;
|
||||
|
||||
private readonly LanguageContext _lc;
|
||||
|
||||
private Dictionary<SiteKey, SiteKey> _sites = new Dictionary<SiteKey, SiteKey>();
|
||||
|
||||
private int LastCleanup;
|
||||
|
||||
private int SitesCreated;
|
||||
|
||||
private Dictionary<int, Func<DynamicOperations, CallSiteBinder, object, object[], object>> _invokers = new Dictionary<int, Func<DynamicOperations, CallSiteBinder, object, object[], object>>();
|
||||
|
||||
public DynamicOperations(LanguageContext lc)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(lc, "lc");
|
||||
_lc = lc;
|
||||
}
|
||||
|
||||
public object Invoke(object obj, params object[] parameters)
|
||||
{
|
||||
return GetInvoker(parameters.Length)(this, _lc.CreateInvokeBinder(new CallInfo(parameters.Length)), obj, parameters);
|
||||
}
|
||||
|
||||
public object InvokeMember(object obj, string memberName, params object[] parameters)
|
||||
{
|
||||
return InvokeMember(obj, memberName, ignoreCase: false, parameters);
|
||||
}
|
||||
|
||||
public object InvokeMember(object obj, string memberName, bool ignoreCase, params object[] parameters)
|
||||
{
|
||||
return GetInvoker(parameters.Length)(this, _lc.CreateCallBinder(memberName, ignoreCase, new CallInfo(parameters.Length)), obj, parameters);
|
||||
}
|
||||
|
||||
public object CreateInstance(object obj, params object[] parameters)
|
||||
{
|
||||
return GetInvoker(parameters.Length)(this, _lc.CreateCreateBinder(new CallInfo(parameters.Length)), obj, parameters);
|
||||
}
|
||||
|
||||
public object GetMember(object obj, string name)
|
||||
{
|
||||
return GetMember(obj, name, ignoreCase: false);
|
||||
}
|
||||
|
||||
public T GetMember<T>(object obj, string name)
|
||||
{
|
||||
return GetMember<T>(obj, name, ignoreCase: false);
|
||||
}
|
||||
|
||||
public bool TryGetMember(object obj, string name, out object value)
|
||||
{
|
||||
return TryGetMember(obj, name, ignoreCase: false, out value);
|
||||
}
|
||||
|
||||
public bool ContainsMember(object obj, string name)
|
||||
{
|
||||
return ContainsMember(obj, name, ignoreCase: false);
|
||||
}
|
||||
|
||||
public void RemoveMember(object obj, string name)
|
||||
{
|
||||
RemoveMember(obj, name, ignoreCase: false);
|
||||
}
|
||||
|
||||
public void SetMember(object obj, string name, object value)
|
||||
{
|
||||
SetMember(obj, name, value, ignoreCase: false);
|
||||
}
|
||||
|
||||
public void SetMember<T>(object obj, string name, T value)
|
||||
{
|
||||
SetMember(obj, name, value, ignoreCase: false);
|
||||
}
|
||||
|
||||
public object GetMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
CallSite<Func<CallSite, object, object>> orCreateSite = GetOrCreateSite<object, object>(_lc.CreateGetMemberBinder(name, ignoreCase));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public T GetMember<T>(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
CallSite<Func<CallSite, object, T>> orCreateSite = GetOrCreateSite<object, T>(_lc.CreateConvertBinder(typeof(T), null));
|
||||
CallSite<Func<CallSite, object, object>> orCreateSite2 = GetOrCreateSite<object, object>(_lc.CreateGetMemberBinder(name, ignoreCase));
|
||||
return orCreateSite.Target(orCreateSite, orCreateSite2.Target(orCreateSite2, obj));
|
||||
}
|
||||
|
||||
public bool TryGetMember(object obj, string name, bool ignoreCase, out object value)
|
||||
{
|
||||
try
|
||||
{
|
||||
value = GetMember(obj, name, ignoreCase);
|
||||
return true;
|
||||
}
|
||||
catch (MissingMemberException)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
object value;
|
||||
return TryGetMember(obj, name, ignoreCase, out value);
|
||||
}
|
||||
|
||||
public void RemoveMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
CallSite<Action<CallSite, object>> orCreateActionSite = GetOrCreateActionSite<object>(_lc.CreateDeleteMemberBinder(name, ignoreCase));
|
||||
orCreateActionSite.Target(orCreateActionSite, obj);
|
||||
}
|
||||
|
||||
public void SetMember(object obj, string name, object value, bool ignoreCase)
|
||||
{
|
||||
CallSite<Func<CallSite, object, object, object>> orCreateSite = GetOrCreateSite<object, object, object>(_lc.CreateSetMemberBinder(name, ignoreCase));
|
||||
orCreateSite.Target(orCreateSite, obj, value);
|
||||
}
|
||||
|
||||
public void SetMember<T>(object obj, string name, T value, bool ignoreCase)
|
||||
{
|
||||
CallSite<Func<CallSite, object, T, object>> orCreateSite = GetOrCreateSite<object, T, object>(_lc.CreateSetMemberBinder(name, ignoreCase));
|
||||
orCreateSite.Target(orCreateSite, obj, value);
|
||||
}
|
||||
|
||||
public T ConvertTo<T>(object obj)
|
||||
{
|
||||
CallSite<Func<CallSite, object, T>> orCreateSite = GetOrCreateSite<object, T>(_lc.CreateConvertBinder(typeof(T), null));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public object ConvertTo(object obj, Type type)
|
||||
{
|
||||
if (type.IsInterface || type.IsClass)
|
||||
{
|
||||
CallSite<Func<CallSite, object, object>> orCreateSite = GetOrCreateSite<object, object>(_lc.CreateConvertBinder(type, null));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
MemberInfo[] member = typeof(DynamicOperations).GetMember("ConvertTo");
|
||||
for (int i = 0; i < member.Length; i++)
|
||||
{
|
||||
MethodInfo methodInfo = (MethodInfo)member[i];
|
||||
if (methodInfo.IsGenericMethod)
|
||||
{
|
||||
try
|
||||
{
|
||||
return methodInfo.MakeGenericMethod(type).Invoke(this, new object[1] { obj });
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
throw ex.InnerException;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public bool TryConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ConvertTo<T>(obj);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ConvertTo(obj, type);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public T ExplicitConvertTo<T>(object obj)
|
||||
{
|
||||
CallSite<Func<CallSite, object, T>> orCreateSite = GetOrCreateSite<object, T>(_lc.CreateConvertBinder(typeof(T), true));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public object ExplicitConvertTo(object obj, Type type)
|
||||
{
|
||||
CallSite<Func<CallSite, object, object>> orCreateSite = GetOrCreateSite<object, object>(_lc.CreateConvertBinder(type, true));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ExplicitConvertTo(obj, type);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ExplicitConvertTo<T>(obj);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public T ImplicitConvertTo<T>(object obj)
|
||||
{
|
||||
CallSite<Func<CallSite, object, T>> orCreateSite = GetOrCreateSite<object, T>(_lc.CreateConvertBinder(typeof(T), false));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public object ImplicitConvertTo(object obj, Type type)
|
||||
{
|
||||
CallSite<Func<CallSite, object, object>> orCreateSite = GetOrCreateSite<object, object>(_lc.CreateConvertBinder(type, false));
|
||||
return orCreateSite.Target(orCreateSite, obj);
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ImplicitConvertTo(obj, type);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
try
|
||||
{
|
||||
result = ImplicitConvertTo<T>(obj);
|
||||
return true;
|
||||
}
|
||||
catch (ArgumentTypeException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public TResult DoOperation<TTarget, TResult>(ExpressionType operation, TTarget target)
|
||||
{
|
||||
CallSite<Func<CallSite, TTarget, TResult>> orCreateSite = GetOrCreateSite<TTarget, TResult>(_lc.CreateUnaryOperationBinder(operation));
|
||||
return orCreateSite.Target(orCreateSite, target);
|
||||
}
|
||||
|
||||
public TResult DoOperation<TTarget, TOther, TResult>(ExpressionType operation, TTarget target, TOther other)
|
||||
{
|
||||
CallSite<Func<CallSite, TTarget, TOther, TResult>> orCreateSite = GetOrCreateSite<TTarget, TOther, TResult>(_lc.CreateBinaryOperationBinder(operation));
|
||||
return orCreateSite.Target(orCreateSite, target, other);
|
||||
}
|
||||
|
||||
public string GetDocumentation(object o)
|
||||
{
|
||||
return _lc.GetDocumentation(o);
|
||||
}
|
||||
|
||||
public IList<string> GetCallSignatures(object o)
|
||||
{
|
||||
return _lc.GetCallSignatures(o);
|
||||
}
|
||||
|
||||
public bool IsCallable(object o)
|
||||
{
|
||||
return _lc.IsCallable(o);
|
||||
}
|
||||
|
||||
public IList<string> GetMemberNames(object obj)
|
||||
{
|
||||
return _lc.GetMemberNames(obj);
|
||||
}
|
||||
|
||||
public string Format(object obj)
|
||||
{
|
||||
return _lc.FormatObject(this, obj);
|
||||
}
|
||||
|
||||
public CallSite<Func<CallSite, T1, TResult>> GetOrCreateSite<T1, TResult>(CallSiteBinder siteBinder)
|
||||
{
|
||||
return GetOrCreateSite(siteBinder, CallSite<Func<CallSite, T1, TResult>>.Create);
|
||||
}
|
||||
|
||||
public CallSite<Action<CallSite, T1>> GetOrCreateActionSite<T1>(CallSiteBinder siteBinder)
|
||||
{
|
||||
return GetOrCreateSite(siteBinder, CallSite<Action<CallSite, T1>>.Create);
|
||||
}
|
||||
|
||||
public CallSite<Func<CallSite, T1, T2, TResult>> GetOrCreateSite<T1, T2, TResult>(CallSiteBinder siteBinder)
|
||||
{
|
||||
return GetOrCreateSite(siteBinder, CallSite<Func<CallSite, T1, T2, TResult>>.Create);
|
||||
}
|
||||
|
||||
public CallSite<Func<CallSite, T1, T2, T3, TResult>> GetOrCreateSite<T1, T2, T3, TResult>(CallSiteBinder siteBinder)
|
||||
{
|
||||
return GetOrCreateSite(siteBinder, CallSite<Func<CallSite, T1, T2, T3, TResult>>.Create);
|
||||
}
|
||||
|
||||
public CallSite<TSiteFunc> GetOrCreateSite<TSiteFunc>(CallSiteBinder siteBinder) where TSiteFunc : class
|
||||
{
|
||||
return GetOrCreateSite(siteBinder, CallSite<TSiteFunc>.Create);
|
||||
}
|
||||
|
||||
private T GetOrCreateSite<T>(CallSiteBinder siteBinder, Func<CallSiteBinder, T> factory) where T : CallSite
|
||||
{
|
||||
SiteKey siteKey = new SiteKey(typeof(T), siteBinder);
|
||||
lock (_sites)
|
||||
{
|
||||
if (!_sites.TryGetValue(siteKey, out var value))
|
||||
{
|
||||
SitesCreated++;
|
||||
if (SitesCreated < 0)
|
||||
{
|
||||
SitesCreated = 0;
|
||||
LastCleanup = 0;
|
||||
}
|
||||
siteKey.Site = factory(siteKey.SiteBinder);
|
||||
_sites[siteKey] = siteKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
siteKey = value;
|
||||
}
|
||||
siteKey.HitCount++;
|
||||
CleanupNoLock();
|
||||
}
|
||||
return (T)siteKey.Site;
|
||||
}
|
||||
|
||||
private void CleanupNoLock()
|
||||
{
|
||||
if (_sites.Count <= 20 || LastCleanup >= SitesCreated - 20)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LastCleanup = SitesCreated;
|
||||
int num = 0;
|
||||
foreach (SiteKey key in _sites.Keys)
|
||||
{
|
||||
num += key.HitCount;
|
||||
}
|
||||
int num2 = num / _sites.Count;
|
||||
if (num2 == 1 && _sites.Count > 50)
|
||||
{
|
||||
_sites.Clear();
|
||||
return;
|
||||
}
|
||||
List<SiteKey> list = null;
|
||||
foreach (SiteKey key2 in _sites.Keys)
|
||||
{
|
||||
if (key2.HitCount < num2 - 2)
|
||||
{
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<SiteKey>();
|
||||
}
|
||||
list.Add(key2);
|
||||
if (list.Count > 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (SiteKey item in list)
|
||||
{
|
||||
_sites.Remove(item);
|
||||
}
|
||||
foreach (SiteKey key3 in _sites.Keys)
|
||||
{
|
||||
key3.HitCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private Func<DynamicOperations, CallSiteBinder, object, object[], object> GetInvoker(int paramCount)
|
||||
{
|
||||
lock (_invokers)
|
||||
{
|
||||
if (!_invokers.TryGetValue(paramCount, out var value))
|
||||
{
|
||||
ParameterExpression parameterExpression = Expression.Parameter(typeof(DynamicOperations));
|
||||
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(CallSiteBinder));
|
||||
ParameterExpression parameterExpression3 = Expression.Parameter(typeof(object));
|
||||
ParameterExpression parameterExpression4 = Expression.Parameter(typeof(object[]));
|
||||
Type objectCallSiteDelegateType = ReflectionUtils.GetObjectCallSiteDelegateType(paramCount);
|
||||
ParameterExpression parameterExpression5 = Expression.Parameter(typeof(CallSite<>).MakeGenericType(objectCallSiteDelegateType));
|
||||
Expression[] array = new Expression[paramCount + 2];
|
||||
array[0] = parameterExpression5;
|
||||
array[1] = parameterExpression3;
|
||||
for (int i = 0; i < paramCount; i++)
|
||||
{
|
||||
array[i + 2] = Expression.ArrayIndex(parameterExpression4, Expression.Constant(i));
|
||||
}
|
||||
MethodInfo genericMethodDefinition = new Func<CallSiteBinder, CallSite<Func<object>>>(GetOrCreateSite<Func<object>>).Method.GetGenericMethodDefinition();
|
||||
return _invokers[paramCount] = Expression.Lambda<Func<DynamicOperations, CallSiteBinder, object, object[], object>>(Expression.Block(new ParameterExpression[1] { parameterExpression5 }, Expression.Assign(parameterExpression5, Expression.Call(parameterExpression, genericMethodDefinition.MakeGenericMethod(objectCallSiteDelegateType), parameterExpression2)), Expression.Invoke(Expression.Field(parameterExpression5, parameterExpression5.Type.GetField("Target")), array)), new ParameterExpression[4] { parameterExpression, parameterExpression2, parameterExpression3, parameterExpression4 }).Compile();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
[Serializable]
|
||||
public abstract class DynamicRuntimeHostingProvider
|
||||
{
|
||||
public abstract PlatformAdaptationLayer PlatformAdaptationLayer { get; }
|
||||
}
|
18
AspClassic.Scripting/Runtime/InvariantContext.cs
Normal file
18
AspClassic.Scripting/Runtime/InvariantContext.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal sealed class InvariantContext : LanguageContext
|
||||
{
|
||||
public override bool CanCreateSourceCode => false;
|
||||
|
||||
internal InvariantContext(ScriptDomainManager manager)
|
||||
: base(manager)
|
||||
{
|
||||
}
|
||||
|
||||
public override ScriptCode CompileSourceCode(SourceUnit sourceUnit, CompilerOptions options, ErrorSink errorSink)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.Text;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal sealed class LanguageBoundTextContentProvider : TextContentProvider
|
||||
{
|
||||
private readonly LanguageContext _context;
|
||||
|
||||
private readonly StreamContentProvider _streamProvider;
|
||||
|
||||
private readonly Encoding _defaultEncoding;
|
||||
|
||||
private readonly string _path;
|
||||
|
||||
public LanguageBoundTextContentProvider(LanguageContext context, StreamContentProvider streamProvider, Encoding defaultEncoding, string path)
|
||||
{
|
||||
_context = context;
|
||||
_streamProvider = streamProvider;
|
||||
_defaultEncoding = defaultEncoding;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
public override SourceCodeReader GetReader()
|
||||
{
|
||||
return _context.GetSourceReader(_streamProvider.GetStream(), _defaultEncoding, _path);
|
||||
}
|
||||
}
|
67
AspClassic.Scripting/Runtime/LanguageConfiguration.cs
Normal file
67
AspClassic.Scripting/Runtime/LanguageConfiguration.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal sealed class LanguageConfiguration
|
||||
{
|
||||
private readonly AssemblyQualifiedTypeName _providerName;
|
||||
|
||||
private readonly string _displayName;
|
||||
|
||||
private readonly IDictionary<string, object> _options;
|
||||
|
||||
private LanguageContext _context;
|
||||
|
||||
public LanguageContext LanguageContext => _context;
|
||||
|
||||
public AssemblyQualifiedTypeName ProviderName => _providerName;
|
||||
|
||||
public string DisplayName => _displayName;
|
||||
|
||||
public LanguageConfiguration(AssemblyQualifiedTypeName providerName, string displayName, IDictionary<string, object> options)
|
||||
{
|
||||
_providerName = providerName;
|
||||
_displayName = displayName;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
internal LanguageContext LoadLanguageContext(ScriptDomainManager domainManager, out bool alreadyLoaded)
|
||||
{
|
||||
if (_context == null)
|
||||
{
|
||||
Assembly assembly = domainManager.Platform.LoadAssembly(_providerName.AssemblyName.FullName);
|
||||
Type type = assembly.GetType(_providerName.TypeName);
|
||||
if (type == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to load language '{_displayName}': assembly '{assembly.Location}' does not contain type '{_providerName.TypeName}'");
|
||||
}
|
||||
if (!type.IsSubclassOf(typeof(LanguageContext)))
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to load language '{_displayName}': type '{type}' is not a valid language provider because it does not inherit from LanguageContext");
|
||||
}
|
||||
LanguageContext value;
|
||||
try
|
||||
{
|
||||
value = (LanguageContext)Activator.CreateInstance(type, domainManager, _options);
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
throw new TargetInvocationException($"Failed to load language '{_displayName}': {ex.InnerException.Message}", ex.InnerException);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new InvalidImplementationException(Strings.InvalidCtorImplementation(type, ex2.Message), ex2);
|
||||
}
|
||||
alreadyLoaded = Interlocked.CompareExchange(ref _context, value, null) != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
alreadyLoaded = true;
|
||||
}
|
||||
return _context;
|
||||
}
|
||||
}
|
465
AspClassic.Scripting/Runtime/LanguageContext.cs
Normal file
465
AspClassic.Scripting/Runtime/LanguageContext.cs
Normal file
|
@ -0,0 +1,465 @@
|
|||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public abstract class LanguageContext
|
||||
{
|
||||
private sealed class DefaultUnaryOperationBinder : UnaryOperationBinder
|
||||
{
|
||||
internal DefaultUnaryOperationBinder(ExpressionType operation)
|
||||
: base(operation)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackUnaryOperation(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, target, new DynamicMetaObject[1] { target }, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DefaultBinaryOperationBinder : BinaryOperationBinder
|
||||
{
|
||||
internal DefaultBinaryOperationBinder(ExpressionType operation)
|
||||
: base(operation)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, target, new DynamicMetaObject[2] { target, arg }, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultConvertAction : ConvertBinder
|
||||
{
|
||||
internal DefaultConvertAction(Type type, bool @explicit)
|
||||
: base(type, @explicit)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackConvert(DynamicMetaObject self, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
if (base.Type.IsAssignableFrom(self.LimitType))
|
||||
{
|
||||
return new DynamicMetaObject(Expression.Convert(self.Expression, base.Type), BindingRestrictions.GetTypeRestriction(self.Expression, self.LimitType));
|
||||
}
|
||||
if (errorSuggestion != null)
|
||||
{
|
||||
return errorSuggestion;
|
||||
}
|
||||
return new DynamicMetaObject(Expression.Throw(Expression.Constant(new ArgumentTypeException($"Expected {base.Type.FullName}, got {self.LimitType.FullName}")), ReturnType), BindingRestrictions.GetTypeRestriction(self.Expression, self.LimitType));
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultGetMemberAction : GetMemberBinder
|
||||
{
|
||||
internal DefaultGetMemberAction(string name, bool ignoreCase)
|
||||
: base(name, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject self, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.New(typeof(MissingMemberException).GetConstructor(new Type[1] { typeof(string) }), Expression.Constant($"unknown member: {base.Name}")), typeof(object)), (self.Value == null) ? BindingRestrictions.GetExpressionRestriction(Expression.Equal(self.Expression, Expression.Constant(null))) : BindingRestrictions.GetTypeRestriction(self.Expression, self.Value.GetType()));
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultSetMemberAction : SetMemberBinder
|
||||
{
|
||||
internal DefaultSetMemberAction(string name, bool ignoreCase)
|
||||
: base(name, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject self, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, self, new DynamicMetaObject[1] { value }, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultDeleteMemberAction : DeleteMemberBinder
|
||||
{
|
||||
internal DefaultDeleteMemberAction(string name, bool ignoreCase)
|
||||
: base(name, ignoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackDeleteMember(DynamicMetaObject self, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, self, DynamicMetaObject.EmptyMetaObjects, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultCallAction : InvokeMemberBinder
|
||||
{
|
||||
private LanguageContext _context;
|
||||
|
||||
internal DefaultCallAction(LanguageContext context, string name, bool ignoreCase, CallInfo callInfo)
|
||||
: base(name, ignoreCase, callInfo)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, target, args.AddFirst(target), errorSuggestion);
|
||||
}
|
||||
|
||||
private static Expression[] GetArgs(DynamicMetaObject target, DynamicMetaObject[] args)
|
||||
{
|
||||
Expression[] array = new Expression[args.Length + 1];
|
||||
array[0] = target.Expression;
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
array[1 + i] = args[i].Expression;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return new DynamicMetaObject(Expression.Dynamic(_context.CreateInvokeBinder(base.CallInfo), typeof(object), GetArgs(target, args)), target.Restrictions.Merge(BindingRestrictions.Combine(args)));
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultInvokeAction : InvokeBinder
|
||||
{
|
||||
internal DefaultInvokeAction(CallInfo callInfo)
|
||||
: base(callInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, target, args, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultCreateAction : CreateInstanceBinder
|
||||
{
|
||||
internal DefaultCreateAction(CallInfo callInfo)
|
||||
: base(callInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return ErrorMetaObject(ReturnType, target, args, errorSuggestion);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ScriptDomainManager _domainManager;
|
||||
|
||||
private readonly ContextId _id;
|
||||
|
||||
private DynamicOperations _operations;
|
||||
|
||||
public ContextId ContextId => _id;
|
||||
|
||||
public ScriptDomainManager DomainManager => _domainManager;
|
||||
|
||||
public virtual bool CanCreateSourceCode => true;
|
||||
|
||||
public virtual Version LanguageVersion => new Version(0, 0);
|
||||
|
||||
public virtual Guid LanguageGuid => Guid.Empty;
|
||||
|
||||
public virtual Guid VendorGuid => Guid.Empty;
|
||||
|
||||
public virtual LanguageOptions Options => new LanguageOptions();
|
||||
|
||||
public DynamicOperations Operations
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_operations == null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _operations, new DynamicOperations(this), null);
|
||||
}
|
||||
return _operations;
|
||||
}
|
||||
}
|
||||
|
||||
protected LanguageContext(ScriptDomainManager domainManager)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(domainManager, "domainManager");
|
||||
_domainManager = domainManager;
|
||||
_id = domainManager.GenerateContextId();
|
||||
}
|
||||
|
||||
public virtual Scope GetScope(string path)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScopeExtension EnsureScopeExtension(Scope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ScopeExtension extension = scope.GetExtension(ContextId);
|
||||
if (extension == null)
|
||||
{
|
||||
extension = CreateScopeExtension(scope);
|
||||
if (extension == null)
|
||||
{
|
||||
throw Error.MustReturnScopeExtension();
|
||||
}
|
||||
return scope.SetExtension(ContextId, extension);
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
public virtual ScopeExtension CreateScopeExtension(Scope scope)
|
||||
{
|
||||
return new ScopeExtension(scope);
|
||||
}
|
||||
|
||||
public virtual void ScopeSetVariable(Scope scope, string name, object value)
|
||||
{
|
||||
Operations.SetMember(scope, name, value);
|
||||
}
|
||||
|
||||
public virtual bool ScopeTryGetVariable(Scope scope, string name, out dynamic value)
|
||||
{
|
||||
return Operations.TryGetMember(scope, name, out value);
|
||||
}
|
||||
|
||||
public virtual T ScopeGetVariable<T>(Scope scope, string name)
|
||||
{
|
||||
return Operations.GetMember<T>(scope, name);
|
||||
}
|
||||
|
||||
public virtual dynamic ScopeGetVariable(Scope scope, string name)
|
||||
{
|
||||
return Operations.GetMember(scope, name);
|
||||
}
|
||||
|
||||
public virtual SourceCodeReader GetSourceReader(Stream stream, Encoding defaultEncoding, string path)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(defaultEncoding, "defaultEncoding");
|
||||
ContractUtils.Requires(stream.CanRead && stream.CanSeek, "stream", "The stream must support reading and seeking");
|
||||
StreamReader streamReader = new StreamReader(stream, defaultEncoding, detectEncodingFromByteOrderMarks: true);
|
||||
streamReader.Peek();
|
||||
return new SourceCodeReader(streamReader, streamReader.CurrentEncoding);
|
||||
}
|
||||
|
||||
public virtual CompilerOptions GetCompilerOptions()
|
||||
{
|
||||
return new CompilerOptions();
|
||||
}
|
||||
|
||||
public virtual CompilerOptions GetCompilerOptions(Scope scope)
|
||||
{
|
||||
return GetCompilerOptions();
|
||||
}
|
||||
|
||||
public abstract ScriptCode CompileSourceCode(SourceUnit sourceUnit, CompilerOptions options, ErrorSink errorSink);
|
||||
|
||||
public virtual ScriptCode LoadCompiledCode(Delegate method, string path, string customData)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public virtual int ExecuteProgram(SourceUnit program)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(program, "program");
|
||||
object obj = program.Execute();
|
||||
if (obj == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
CallSite<Func<CallSite, object, int>> callSite = CallSite<Func<CallSite, object, int>>.Create(CreateConvertBinder(typeof(int), true));
|
||||
return callSite.Target(callSite, obj);
|
||||
}
|
||||
|
||||
public virtual void SetSearchPaths(ICollection<string> paths)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public virtual ICollection<string> GetSearchPaths()
|
||||
{
|
||||
return Options.SearchPaths;
|
||||
}
|
||||
|
||||
public virtual SourceUnit GenerateSourceCode(CodeObject codeDom, string path, SourceCodeKind kind)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual TService GetService<TService>(params object[] args) where TService : class
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void Shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual string FormatException(Exception exception)
|
||||
{
|
||||
return exception.ToString();
|
||||
}
|
||||
|
||||
public SourceUnit CreateSnippet(string code, SourceCodeKind kind)
|
||||
{
|
||||
return CreateSnippet(code, null, kind);
|
||||
}
|
||||
|
||||
public SourceUnit CreateSnippet(string code, string id, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(code, "code");
|
||||
return CreateSourceUnit(new SourceStringContentProvider(code), id, kind);
|
||||
}
|
||||
|
||||
public SourceUnit CreateFileUnit(string path)
|
||||
{
|
||||
return CreateFileUnit(path, StringUtils.DefaultEncoding);
|
||||
}
|
||||
|
||||
public SourceUnit CreateFileUnit(string path, Encoding encoding)
|
||||
{
|
||||
return CreateFileUnit(path, encoding, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public SourceUnit CreateFileUnit(string path, Encoding encoding, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(path, "path");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
TextContentProvider contentProvider = new LanguageBoundTextContentProvider(this, new FileStreamContentProvider(DomainManager.Platform, path), encoding, path);
|
||||
return CreateSourceUnit(contentProvider, path, kind);
|
||||
}
|
||||
|
||||
public SourceUnit CreateFileUnit(string path, string content)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(path, "path");
|
||||
ContractUtils.RequiresNotNull(content, "content");
|
||||
TextContentProvider contentProvider = new SourceStringContentProvider(content);
|
||||
return CreateSourceUnit(contentProvider, path, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public SourceUnit CreateSourceUnit(StreamContentProvider contentProvider, string path, Encoding encoding, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(contentProvider, "contentProvider");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
ContractUtils.Requires(CanCreateSourceCode);
|
||||
return new SourceUnit(this, new LanguageBoundTextContentProvider(this, contentProvider, encoding, path), path, kind);
|
||||
}
|
||||
|
||||
public SourceUnit CreateSourceUnit(TextContentProvider contentProvider, string path, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(contentProvider, "contentProvider");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
ContractUtils.Requires(CanCreateSourceCode);
|
||||
return new SourceUnit(this, contentProvider, path, kind);
|
||||
}
|
||||
|
||||
public virtual ErrorSink GetCompilerErrorSink()
|
||||
{
|
||||
return ErrorSink.Null;
|
||||
}
|
||||
|
||||
internal static DynamicMetaObject ErrorMetaObject(Type resultType, DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
|
||||
{
|
||||
return errorSuggestion ?? new DynamicMetaObject(Expression.Throw(Expression.New(typeof(NotImplementedException)), resultType), target.Restrictions.Merge(BindingRestrictions.Combine(args)));
|
||||
}
|
||||
|
||||
public virtual UnaryOperationBinder CreateUnaryOperationBinder(ExpressionType operation)
|
||||
{
|
||||
return new DefaultUnaryOperationBinder(operation);
|
||||
}
|
||||
|
||||
public virtual BinaryOperationBinder CreateBinaryOperationBinder(ExpressionType operation)
|
||||
{
|
||||
return new DefaultBinaryOperationBinder(operation);
|
||||
}
|
||||
|
||||
public virtual ConvertBinder CreateConvertBinder(Type toType, bool? explicitCast)
|
||||
{
|
||||
return new DefaultConvertAction(toType, explicitCast ?? false);
|
||||
}
|
||||
|
||||
public virtual GetMemberBinder CreateGetMemberBinder(string name, bool ignoreCase)
|
||||
{
|
||||
return new DefaultGetMemberAction(name, ignoreCase);
|
||||
}
|
||||
|
||||
public virtual SetMemberBinder CreateSetMemberBinder(string name, bool ignoreCase)
|
||||
{
|
||||
return new DefaultSetMemberAction(name, ignoreCase);
|
||||
}
|
||||
|
||||
public virtual DeleteMemberBinder CreateDeleteMemberBinder(string name, bool ignoreCase)
|
||||
{
|
||||
return new DefaultDeleteMemberAction(name, ignoreCase);
|
||||
}
|
||||
|
||||
public virtual InvokeMemberBinder CreateCallBinder(string name, bool ignoreCase, CallInfo callInfo)
|
||||
{
|
||||
return new DefaultCallAction(this, name, ignoreCase, callInfo);
|
||||
}
|
||||
|
||||
public virtual InvokeBinder CreateInvokeBinder(CallInfo callInfo)
|
||||
{
|
||||
return new DefaultInvokeAction(callInfo);
|
||||
}
|
||||
|
||||
public virtual CreateInstanceBinder CreateCreateBinder(CallInfo callInfo)
|
||||
{
|
||||
return new DefaultCreateAction(callInfo);
|
||||
}
|
||||
|
||||
public virtual IList<string> GetMemberNames(object obj)
|
||||
{
|
||||
if (obj is IDynamicMetaObjectProvider dynamicMetaObjectProvider)
|
||||
{
|
||||
DynamicMetaObject metaObject = dynamicMetaObjectProvider.GetMetaObject(Expression.Parameter(typeof(object), null));
|
||||
return metaObject.GetDynamicMemberNames().ToReadOnly();
|
||||
}
|
||||
return AspClassic.Scripting.Utils.EmptyArray<string>.Instance;
|
||||
}
|
||||
|
||||
public virtual string GetDocumentation(object obj)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public virtual IList<string> GetCallSignatures(object obj)
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
public virtual bool IsCallable(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return typeof(Delegate).IsAssignableFrom(obj.GetType());
|
||||
}
|
||||
|
||||
public virtual string FormatObject(DynamicOperations operations, object obj)
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
return obj.ToString();
|
||||
}
|
||||
return "null";
|
||||
}
|
||||
|
||||
public virtual void GetExceptionMessage(Exception exception, out string message, out string errorTypeName)
|
||||
{
|
||||
message = exception.Message;
|
||||
errorTypeName = exception.GetType().Name;
|
||||
}
|
||||
}
|
8
AspClassic.Scripting/Runtime/NotNullAttribute.cs
Normal file
8
AspClassic.Scripting/Runtime/NotNullAttribute.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class NotNullAttribute : Attribute
|
||||
{
|
||||
}
|
8
AspClassic.Scripting/Runtime/NotNullItemsAttribute.cs
Normal file
8
AspClassic.Scripting/Runtime/NotNullItemsAttribute.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class NotNullItemsAttribute : Attribute
|
||||
{
|
||||
}
|
101
AspClassic.Scripting/Runtime/Operators.cs
Normal file
101
AspClassic.Scripting/Runtime/Operators.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
[Obsolete("Use ExpressionType instead")]
|
||||
public enum Operators
|
||||
{
|
||||
None = 0,
|
||||
Call = 1,
|
||||
CodeRepresentation = 2,
|
||||
MemberNames = 3,
|
||||
Documentation = 4,
|
||||
CallSignatures = 5,
|
||||
IsCallable = 6,
|
||||
Add = 7,
|
||||
Subtract = 8,
|
||||
Power = 9,
|
||||
Multiply = 10,
|
||||
FloorDivide = 11,
|
||||
Divide = 12,
|
||||
TrueDivide = 13,
|
||||
Mod = 14,
|
||||
LeftShift = 15,
|
||||
RightShift = 16,
|
||||
BitwiseAnd = 17,
|
||||
BitwiseOr = 18,
|
||||
ExclusiveOr = 19,
|
||||
LessThan = 20,
|
||||
GreaterThan = 21,
|
||||
LessThanOrEqual = 22,
|
||||
GreaterThanOrEqual = 23,
|
||||
Equals = 24,
|
||||
NotEquals = 25,
|
||||
LessThanGreaterThan = 26,
|
||||
InPlaceAdd = 27,
|
||||
InPlaceSubtract = 28,
|
||||
InPlacePower = 29,
|
||||
InPlaceMultiply = 30,
|
||||
InPlaceFloorDivide = 31,
|
||||
InPlaceDivide = 32,
|
||||
InPlaceTrueDivide = 33,
|
||||
InPlaceMod = 34,
|
||||
InPlaceLeftShift = 35,
|
||||
InPlaceRightShift = 36,
|
||||
InPlaceBitwiseAnd = 37,
|
||||
InPlaceBitwiseOr = 38,
|
||||
InPlaceExclusiveOr = 39,
|
||||
ReverseAdd = 40,
|
||||
ReverseSubtract = 41,
|
||||
ReversePower = 42,
|
||||
ReverseMultiply = 43,
|
||||
ReverseFloorDivide = 44,
|
||||
ReverseDivide = 45,
|
||||
ReverseTrueDivide = 46,
|
||||
ReverseMod = 47,
|
||||
ReverseLeftShift = 48,
|
||||
ReverseRightShift = 49,
|
||||
ReverseBitwiseAnd = 50,
|
||||
ReverseBitwiseOr = 51,
|
||||
ReverseExclusiveOr = 52,
|
||||
Contains = 53,
|
||||
GetItem = 54,
|
||||
SetItem = 55,
|
||||
DeleteItem = 56,
|
||||
GetSlice = 57,
|
||||
SetSlice = 58,
|
||||
DeleteSlice = 59,
|
||||
Length = 60,
|
||||
Compare = 61,
|
||||
DivMod = 62,
|
||||
ReverseDivMod = 63,
|
||||
GetMember = 64,
|
||||
GetBoundMember = 65,
|
||||
SetMember = 66,
|
||||
DeleteMember = 67,
|
||||
GetMemberNames = 68,
|
||||
AbsoluteValue = 69,
|
||||
Positive = 70,
|
||||
Negate = 71,
|
||||
OnesComplement = 72,
|
||||
RightShiftUnsigned = 73,
|
||||
InPlaceRightShiftUnsigned = 74,
|
||||
ReverseRightShiftUnsigned = 75,
|
||||
RightShiftSigned = 76,
|
||||
Not = 77,
|
||||
Increment = 78,
|
||||
Decrement = 79,
|
||||
Assign = 80,
|
||||
IsFalse = 81,
|
||||
IsTrue = 82,
|
||||
Or = 83,
|
||||
And = 84,
|
||||
IntegralDivide = 85,
|
||||
Concatenate = 86,
|
||||
Like = 87,
|
||||
Comma = 88,
|
||||
GetEnumerator = 89,
|
||||
Dispose = 90,
|
||||
IdMask = int.MaxValue,
|
||||
UserDefinedFlag = int.MinValue
|
||||
}
|
34
AspClassic.Scripting/Runtime/ParserSink.cs
Normal file
34
AspClassic.Scripting/Runtime/ParserSink.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public class ParserSink
|
||||
{
|
||||
public static readonly ParserSink Null = new ParserSink();
|
||||
|
||||
public virtual void MatchPair(SourceSpan opening, SourceSpan closing, int priority)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void MatchTriple(SourceSpan opening, SourceSpan middle, SourceSpan closing, int priority)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void EndParameters(SourceSpan span)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void NextParameter(SourceSpan span)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void QualifyName(SourceSpan selector, SourceSpan span, string name)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void StartName(SourceSpan span, string name)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void StartParameters(SourceSpan context)
|
||||
{
|
||||
}
|
||||
}
|
198
AspClassic.Scripting/Runtime/Scope.cs
Normal file
198
AspClassic.Scripting/Runtime/Scope.cs
Normal file
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public sealed class Scope : IDynamicMetaObjectProvider
|
||||
{
|
||||
internal sealed class MetaScope : DynamicMetaObject
|
||||
{
|
||||
private DynamicMetaObject StorageMetaObject => DynamicMetaObject.Create(Value._storage, StorageExpression);
|
||||
|
||||
private MemberExpression StorageExpression => Expression.Property(Expression.Convert(base.Expression, typeof(Scope)), typeof(Scope).GetProperty("Storage"));
|
||||
|
||||
public new Scope Value => (Scope)base.Value;
|
||||
|
||||
public MetaScope(Expression parameter, Scope scope)
|
||||
: base(parameter, BindingRestrictions.Empty, scope)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
|
||||
{
|
||||
return Restrict(binder.Bind(StorageMetaObject, DynamicMetaObject.EmptyMetaObjects));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
|
||||
{
|
||||
return Restrict(binder.Bind(StorageMetaObject, args));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
|
||||
{
|
||||
return Restrict(binder.Bind(StorageMetaObject, new DynamicMetaObject[1] { value }));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
|
||||
{
|
||||
return Restrict(binder.Bind(StorageMetaObject, DynamicMetaObject.EmptyMetaObjects));
|
||||
}
|
||||
|
||||
private DynamicMetaObject Restrict(DynamicMetaObject result)
|
||||
{
|
||||
if (base.Expression.Type == typeof(Scope))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return new DynamicMetaObject(result.Expression, BindingRestrictions.GetTypeRestriction(base.Expression, typeof(Scope)).Merge(result.Restrictions));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return StorageMetaObject.GetDynamicMemberNames();
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AttributesAdapter : IDynamicMetaObjectProvider
|
||||
{
|
||||
internal sealed class Meta : DynamicMetaObject
|
||||
{
|
||||
public new AttributesAdapter Value => (AttributesAdapter)base.Value;
|
||||
|
||||
public Meta(Expression parameter, AttributesAdapter storage)
|
||||
: base(parameter, BindingRestrictions.Empty, storage)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
|
||||
{
|
||||
return DynamicTryGetMember(binder.Name, binder.FallbackGetMember(this).Expression, (Expression tmp) => tmp);
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
|
||||
{
|
||||
return DynamicTryGetMember(binder.Name, binder.FallbackInvokeMember(this, args).Expression, (Expression tmp) => binder.FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression);
|
||||
}
|
||||
|
||||
private DynamicMetaObject DynamicTryGetMember(string name, Expression fallback, Func<Expression, Expression> resultOp)
|
||||
{
|
||||
ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
|
||||
return new DynamicMetaObject(Expression.Block(new ParameterExpression[1] { parameterExpression }, Expression.Condition(Expression.NotEqual(Expression.Assign(parameterExpression, Expression.Invoke(Expression.Constant(new Func<object, SymbolId, object>(TryGetMember)), base.Expression, Expression.Constant(SymbolTable.StringToId(name)))), Expression.Constant(_getFailed)), ExpressionUtils.Convert(resultOp(parameterExpression), typeof(object)), ExpressionUtils.Convert(fallback, typeof(object)))), GetRestrictions());
|
||||
}
|
||||
|
||||
private BindingRestrictions GetRestrictions()
|
||||
{
|
||||
return BindingRestrictions.GetTypeRestriction(base.Expression, typeof(AttributesAdapter));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
|
||||
{
|
||||
return new DynamicMetaObject(Expression.Block(Expression.Invoke(Expression.Constant(new Action<object, SymbolId, object>(TrySetMember)), base.Expression, Expression.Constant(SymbolTable.StringToId(binder.Name)), Expression.Convert(value.Expression, typeof(object))), value.Expression), GetRestrictions());
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
|
||||
{
|
||||
return new DynamicMetaObject(Expression.Condition(Expression.Invoke(Expression.Constant(new Func<object, SymbolId, bool>(TryDeleteMember)), base.Expression, Expression.Constant(SymbolTable.StringToId(binder.Name))), Expression.Default(binder.ReturnType), binder.FallbackDeleteMember(this).Expression), GetRestrictions());
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
foreach (object o in Value._data.Keys)
|
||||
{
|
||||
if (o is string)
|
||||
{
|
||||
yield return (string)o;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IAttributesCollection _data;
|
||||
|
||||
public AttributesAdapter(IAttributesCollection data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
private static object TryGetMember(object adapter, SymbolId name)
|
||||
{
|
||||
if (((AttributesAdapter)adapter)._data.TryGetValue(name, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return _getFailed;
|
||||
}
|
||||
|
||||
private static void TrySetMember(object adapter, SymbolId name, object value)
|
||||
{
|
||||
((AttributesAdapter)adapter)._data[name] = value;
|
||||
}
|
||||
|
||||
private static bool TryDeleteMember(object adapter, SymbolId name)
|
||||
{
|
||||
return ((AttributesAdapter)adapter)._data.Remove(name);
|
||||
}
|
||||
|
||||
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new Meta(parameter, this);
|
||||
}
|
||||
}
|
||||
|
||||
private ScopeExtension[] _extensions;
|
||||
|
||||
private readonly IDynamicMetaObjectProvider _storage;
|
||||
|
||||
private static readonly object _getFailed = new object();
|
||||
|
||||
public dynamic Storage => _storage;
|
||||
|
||||
public Scope()
|
||||
{
|
||||
_extensions = ScopeExtension.EmptyArray;
|
||||
_storage = new ScopeStorage();
|
||||
}
|
||||
|
||||
[Obsolete("IAttributesCollection is obsolete, use Scope(IDynamicMetaObjectProvider) overload instead")]
|
||||
public Scope(IAttributesCollection dictionary)
|
||||
{
|
||||
_extensions = ScopeExtension.EmptyArray;
|
||||
_storage = new AttributesAdapter(dictionary);
|
||||
}
|
||||
|
||||
public Scope(IDynamicMetaObjectProvider storage)
|
||||
{
|
||||
_extensions = ScopeExtension.EmptyArray;
|
||||
_storage = storage;
|
||||
}
|
||||
|
||||
public ScopeExtension GetExtension(ContextId languageContextId)
|
||||
{
|
||||
if (languageContextId.Id >= _extensions.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _extensions[languageContextId.Id];
|
||||
}
|
||||
|
||||
public ScopeExtension SetExtension(ContextId languageContextId, ScopeExtension extension)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(extension, "extension");
|
||||
lock (_extensions)
|
||||
{
|
||||
if (languageContextId.Id >= _extensions.Length)
|
||||
{
|
||||
Array.Resize(ref _extensions, languageContextId.Id + 1);
|
||||
}
|
||||
return _extensions[languageContextId.Id] ?? (_extensions[languageContextId.Id] = extension);
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new MetaScope(parameter, this);
|
||||
}
|
||||
}
|
18
AspClassic.Scripting/Runtime/ScopeExtension.cs
Normal file
18
AspClassic.Scripting/Runtime/ScopeExtension.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public class ScopeExtension
|
||||
{
|
||||
public static readonly ScopeExtension[] EmptyArray = new ScopeExtension[0];
|
||||
|
||||
private readonly Scope _scope;
|
||||
|
||||
public Scope Scope => _scope;
|
||||
|
||||
public ScopeExtension(Scope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
_scope = scope;
|
||||
}
|
||||
}
|
141
AspClassic.Scripting/Runtime/ScriptDomainManager.cs
Normal file
141
AspClassic.Scripting/Runtime/ScriptDomainManager.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public sealed class ScriptDomainManager
|
||||
{
|
||||
private readonly DynamicRuntimeHostingProvider _hostingProvider;
|
||||
|
||||
private readonly SharedIO _sharedIO;
|
||||
|
||||
private List<Assembly> _loadedAssemblies = new List<Assembly>();
|
||||
|
||||
private int _lastContextId;
|
||||
|
||||
private Scope _globals;
|
||||
|
||||
private readonly DlrConfiguration _configuration;
|
||||
|
||||
public PlatformAdaptationLayer Platform
|
||||
{
|
||||
get
|
||||
{
|
||||
PlatformAdaptationLayer platformAdaptationLayer = _hostingProvider.PlatformAdaptationLayer;
|
||||
if (platformAdaptationLayer == null)
|
||||
{
|
||||
throw new InvalidImplementationException();
|
||||
}
|
||||
return platformAdaptationLayer;
|
||||
}
|
||||
}
|
||||
|
||||
public SharedIO SharedIO => _sharedIO;
|
||||
|
||||
public DynamicRuntimeHostingProvider Host => _hostingProvider;
|
||||
|
||||
public DlrConfiguration Configuration => _configuration;
|
||||
|
||||
public Scope Globals
|
||||
{
|
||||
get
|
||||
{
|
||||
return _globals;
|
||||
}
|
||||
set
|
||||
{
|
||||
_globals = value;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<AssemblyLoadedEventArgs> AssemblyLoaded;
|
||||
|
||||
public ScriptDomainManager(DynamicRuntimeHostingProvider hostingProvider, DlrConfiguration configuration)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(hostingProvider, "hostingProvider");
|
||||
ContractUtils.RequiresNotNull(configuration, "configuration");
|
||||
configuration.Freeze();
|
||||
_hostingProvider = hostingProvider;
|
||||
_configuration = configuration;
|
||||
_sharedIO = new SharedIO();
|
||||
_globals = new Scope();
|
||||
}
|
||||
|
||||
internal ContextId GenerateContextId()
|
||||
{
|
||||
return new ContextId(Interlocked.Increment(ref _lastContextId));
|
||||
}
|
||||
|
||||
public LanguageContext GetLanguage(Type providerType)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(providerType, "providerType");
|
||||
return GetLanguageByTypeName(providerType.AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
public LanguageContext GetLanguageByTypeName(string providerAssemblyQualifiedTypeName)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(providerAssemblyQualifiedTypeName, "providerAssemblyQualifiedTypeName");
|
||||
AssemblyQualifiedTypeName providerName = AssemblyQualifiedTypeName.ParseArgument(providerAssemblyQualifiedTypeName, "providerAssemblyQualifiedTypeName");
|
||||
if (!_configuration.TryLoadLanguage(this, providerName, out var language))
|
||||
{
|
||||
throw Error.UnknownLanguageProviderType();
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
public bool TryGetLanguage(string languageName, out LanguageContext language)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(languageName, "languageName");
|
||||
return _configuration.TryLoadLanguage(this, languageName, isExtension: false, out language);
|
||||
}
|
||||
|
||||
public LanguageContext GetLanguageByName(string languageName)
|
||||
{
|
||||
if (!TryGetLanguage(languageName, out var language))
|
||||
{
|
||||
throw new ArgumentException($"Unknown language name: '{languageName}'");
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
public bool TryGetLanguageByFileExtension(string fileExtension, out LanguageContext language)
|
||||
{
|
||||
ContractUtils.RequiresNotEmpty(fileExtension, "fileExtension");
|
||||
return _configuration.TryLoadLanguage(this, DlrConfiguration.NormalizeExtension(fileExtension), isExtension: true, out language);
|
||||
}
|
||||
|
||||
public LanguageContext GetLanguageByExtension(string fileExtension)
|
||||
{
|
||||
if (!TryGetLanguageByFileExtension(fileExtension, out var language))
|
||||
{
|
||||
throw new ArgumentException($"Unknown file extension: '{fileExtension}'");
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
public bool LoadAssembly(Assembly assembly)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(assembly, "assembly");
|
||||
lock (_loadedAssemblies)
|
||||
{
|
||||
if (_loadedAssemblies.Contains(assembly))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_loadedAssemblies.Add(assembly);
|
||||
}
|
||||
this.AssemblyLoaded?.Invoke(this, new AssemblyLoadedEventArgs(assembly));
|
||||
return true;
|
||||
}
|
||||
|
||||
public IList<Assembly> GetLoadedAssemblyList()
|
||||
{
|
||||
lock (_loadedAssemblies)
|
||||
{
|
||||
return _loadedAssemblies.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
307
AspClassic.Scripting/Runtime/SharedIO.cs
Normal file
307
AspClassic.Scripting/Runtime/SharedIO.cs
Normal file
|
@ -0,0 +1,307 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public sealed class SharedIO
|
||||
{
|
||||
private sealed class StreamProxy : Stream
|
||||
{
|
||||
private readonly ConsoleStreamType _type;
|
||||
|
||||
private readonly SharedIO _io;
|
||||
|
||||
public override bool CanRead => _type == ConsoleStreamType.Input;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => !CanRead;
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public StreamProxy(SharedIO io, ConsoleStreamType type)
|
||||
{
|
||||
_io = io;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
_io.GetStream(_type).Flush();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return _io.GetStream(_type).Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_io.GetStream(_type).Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object _mutex = new object();
|
||||
|
||||
private Stream _inputStream;
|
||||
|
||||
private Stream _outputStream;
|
||||
|
||||
private Stream _errorStream;
|
||||
|
||||
private TextReader _inputReader;
|
||||
|
||||
private TextWriter _outputWriter;
|
||||
|
||||
private TextWriter _errorWriter;
|
||||
|
||||
private Encoding _inputEncoding;
|
||||
|
||||
public Stream InputStream
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeInput();
|
||||
return _inputStream;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream OutputStream
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeOutput();
|
||||
return _outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream ErrorStream
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeErrorOutput();
|
||||
return _errorStream;
|
||||
}
|
||||
}
|
||||
|
||||
public TextReader InputReader
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeInput();
|
||||
return _inputReader;
|
||||
}
|
||||
}
|
||||
|
||||
public TextWriter OutputWriter
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeOutput();
|
||||
return _outputWriter;
|
||||
}
|
||||
}
|
||||
|
||||
public TextWriter ErrorWriter
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeErrorOutput();
|
||||
return _errorWriter;
|
||||
}
|
||||
}
|
||||
|
||||
public Encoding InputEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeInput();
|
||||
return _inputEncoding;
|
||||
}
|
||||
}
|
||||
|
||||
public Encoding OutputEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeOutput();
|
||||
return _outputWriter.Encoding;
|
||||
}
|
||||
}
|
||||
|
||||
public Encoding ErrorEncoding
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeErrorOutput();
|
||||
return _errorWriter.Encoding;
|
||||
}
|
||||
}
|
||||
|
||||
internal SharedIO()
|
||||
{
|
||||
}
|
||||
|
||||
private void InitializeInput()
|
||||
{
|
||||
if (_inputStream != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_mutex)
|
||||
{
|
||||
if (_inputStream == null)
|
||||
{
|
||||
_inputStream = ConsoleInputStream.Instance;
|
||||
_inputEncoding = Console.InputEncoding;
|
||||
_inputReader = Console.In;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeOutput()
|
||||
{
|
||||
if (_outputStream != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_mutex)
|
||||
{
|
||||
if (_outputStream == null)
|
||||
{
|
||||
_outputStream = Console.OpenStandardOutput();
|
||||
_outputWriter = Console.Out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeErrorOutput()
|
||||
{
|
||||
if (_errorStream == null)
|
||||
{
|
||||
Stream value = Console.OpenStandardError();
|
||||
Interlocked.CompareExchange(ref _errorStream, value, null);
|
||||
Interlocked.CompareExchange(ref _errorWriter, Console.Error, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOutput(Stream stream, TextWriter writer)
|
||||
{
|
||||
lock (_mutex)
|
||||
{
|
||||
_outputStream = stream;
|
||||
_outputWriter = writer;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetErrorOutput(Stream stream, TextWriter writer)
|
||||
{
|
||||
lock (_mutex)
|
||||
{
|
||||
_errorStream = stream;
|
||||
_errorWriter = writer;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInput(Stream stream, TextReader reader, Encoding encoding)
|
||||
{
|
||||
lock (_mutex)
|
||||
{
|
||||
_inputStream = stream;
|
||||
_inputReader = reader;
|
||||
_inputEncoding = encoding;
|
||||
}
|
||||
}
|
||||
|
||||
public void RedirectToConsole()
|
||||
{
|
||||
lock (_mutex)
|
||||
{
|
||||
_inputEncoding = null;
|
||||
_inputStream = null;
|
||||
_outputStream = null;
|
||||
_errorStream = null;
|
||||
_inputReader = null;
|
||||
_outputWriter = null;
|
||||
_errorWriter = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream(ConsoleStreamType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ConsoleStreamType.Input => InputStream,
|
||||
ConsoleStreamType.Output => OutputStream,
|
||||
ConsoleStreamType.ErrorOutput => ErrorStream,
|
||||
_ => throw Error.InvalidStreamType(type),
|
||||
};
|
||||
}
|
||||
|
||||
public TextWriter GetWriter(ConsoleStreamType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ConsoleStreamType.Output => OutputWriter,
|
||||
ConsoleStreamType.ErrorOutput => ErrorWriter,
|
||||
_ => throw Error.InvalidStreamType(type),
|
||||
};
|
||||
}
|
||||
|
||||
public Encoding GetEncoding(ConsoleStreamType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ConsoleStreamType.Input => InputEncoding,
|
||||
ConsoleStreamType.Output => OutputEncoding,
|
||||
ConsoleStreamType.ErrorOutput => ErrorEncoding,
|
||||
_ => throw Error.InvalidStreamType(type),
|
||||
};
|
||||
}
|
||||
|
||||
public TextReader GetReader(out Encoding encoding)
|
||||
{
|
||||
lock (_mutex)
|
||||
{
|
||||
TextReader inputReader = InputReader;
|
||||
encoding = InputEncoding;
|
||||
return inputReader;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStreamProxy(ConsoleStreamType type)
|
||||
{
|
||||
return new StreamProxy(this, type);
|
||||
}
|
||||
}
|
575
AspClassic.Scripting/Runtime/SymbolDictionary.cs
Normal file
575
AspClassic.Scripting/Runtime/SymbolDictionary.cs
Normal file
|
@ -0,0 +1,575 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal sealed class SymbolDictionary : BaseSymbolDictionary, IDictionary, ICollection, IDictionary<object, object>, ICollection<KeyValuePair<object, object>>, IAttributesCollection, IEnumerable<KeyValuePair<object, object>>, IEnumerable
|
||||
{
|
||||
private Dictionary<SymbolId, object> _data = new Dictionary<SymbolId, object>();
|
||||
|
||||
ICollection<object> IDictionary<object, object>.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
lock (this)
|
||||
{
|
||||
foreach (SymbolId key in _data.Keys)
|
||||
{
|
||||
if (!(key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
list.Add(SymbolTable.IdToString(key));
|
||||
}
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists != null)
|
||||
{
|
||||
list.AddRange(objectKeysDictionaryIfExists.Keys);
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ICollection<object> IDictionary<object, object>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists == null)
|
||||
{
|
||||
return _data.Values;
|
||||
}
|
||||
List<object> list = new List<object>();
|
||||
foreach (KeyValuePair<SymbolId, object> datum in _data)
|
||||
{
|
||||
if (!(datum.Key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
list.Add(datum.Value);
|
||||
}
|
||||
}
|
||||
foreach (object value in objectKeysDictionaryIfExists.Values)
|
||||
{
|
||||
list.Add(value);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
if (_data.TryGetValue(SymbolTable.StringToId(text), out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists != null)
|
||||
{
|
||||
return objectKeysDictionaryIfExists[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new KeyNotFoundException($"'{key}'");
|
||||
}
|
||||
set
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
_data[SymbolTable.StringToId(text)] = value;
|
||||
return;
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionary = GetObjectKeysDictionary();
|
||||
objectKeysDictionary[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
int num = _data.Count;
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists != null)
|
||||
{
|
||||
num += objectKeysDictionaryIfExists.Count - 1;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
object IAttributesCollection.this[SymbolId name]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return _data[name];
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_data[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<SymbolId, object> SymbolAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (GetObjectKeysDictionaryIfExists() == null)
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
Dictionary<SymbolId, object> dictionary = new Dictionary<SymbolId, object>();
|
||||
foreach (KeyValuePair<SymbolId, object> datum in _data)
|
||||
{
|
||||
if (!(datum.Key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
dictionary.Add(datum.Key, datum.Value);
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<object> Keys => AsObjectKeyedDictionary().Keys;
|
||||
|
||||
public bool IsFixedSize => false;
|
||||
|
||||
ICollection IDictionary.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
lock (this)
|
||||
{
|
||||
foreach (SymbolId key in _data.Keys)
|
||||
{
|
||||
if (!(key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
list.Add(SymbolTable.IdToString(key));
|
||||
}
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists != null)
|
||||
{
|
||||
list.AddRange(objectKeysDictionaryIfExists.Keys);
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ICollection IDictionary.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
lock (this)
|
||||
{
|
||||
foreach (KeyValuePair<SymbolId, object> datum in _data)
|
||||
{
|
||||
if (!(datum.Key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
list.Add(datum.Value);
|
||||
}
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists != null)
|
||||
{
|
||||
list.AddRange(objectKeysDictionaryIfExists.Values);
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object IDictionary.this[object key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return AsObjectKeyedDictionary()[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
AsObjectKeyedDictionary()[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSynchronized => true;
|
||||
|
||||
public object SyncRoot => this;
|
||||
|
||||
public SymbolDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
public SymbolDictionary(IAttributesCollection from)
|
||||
{
|
||||
lock (from)
|
||||
{
|
||||
foreach (KeyValuePair<object, object> item in from)
|
||||
{
|
||||
AsObjectKeyedDictionary().Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<object, object> GetObjectKeysDictionary()
|
||||
{
|
||||
Dictionary<object, object> dictionary = GetObjectKeysDictionaryIfExists();
|
||||
if (dictionary == null)
|
||||
{
|
||||
dictionary = new Dictionary<object, object>();
|
||||
_data.Add(BaseSymbolDictionary.ObjectKeys, dictionary);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private Dictionary<object, object> GetObjectKeysDictionaryIfExists()
|
||||
{
|
||||
if (_data.TryGetValue(BaseSymbolDictionary.ObjectKeys, out var value))
|
||||
{
|
||||
return (Dictionary<object, object>)value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void IDictionary<object, object>.Add(object key, object value)
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
_data.Add(SymbolTable.StringToId(text), value);
|
||||
return;
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionary = GetObjectKeysDictionary();
|
||||
objectKeysDictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDictionary<object, object>.ContainsKey(object key)
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
if (!SymbolTable.StringHasId(text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _data.ContainsKey(SymbolTable.StringToId(text));
|
||||
}
|
||||
return GetObjectKeysDictionaryIfExists()?.ContainsKey(key) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDictionary<object, object>.Remove(object key)
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
return _data.Remove(SymbolTable.StringToId(text));
|
||||
}
|
||||
return GetObjectKeysDictionaryIfExists()?.Remove(key) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IDictionary<object, object>.TryGetValue(object key, out object value)
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
return _data.TryGetValue(SymbolTable.StringToId(text), out value);
|
||||
}
|
||||
value = null;
|
||||
return GetObjectKeysDictionaryIfExists()?.TryGetValue(key, out value) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<object, object> item)
|
||||
{
|
||||
string text = item.Key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
_data.Add(SymbolTable.StringToId(text), item.Value);
|
||||
return;
|
||||
}
|
||||
Dictionary<object, object> objectKeysDictionary = GetObjectKeysDictionary();
|
||||
objectKeysDictionary[item.Key] = item.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_data.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<object, object> item)
|
||||
{
|
||||
if (AsObjectKeyedDictionary().TryGetValue(item.Key, out var value) && value == item.Value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
lock (this)
|
||||
{
|
||||
ContractUtils.RequiresArrayRange(array, arrayIndex, Count, "arrayIndex", "array");
|
||||
foreach (KeyValuePair<object, object> item in (IEnumerable<KeyValuePair<object, object>>)this)
|
||||
{
|
||||
array[arrayIndex++] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<object, object> item)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (item.Key is string text && AsObjectKeyedDictionary().TryGetValue(text, out var value) && value == item.Value)
|
||||
{
|
||||
_data.Remove(SymbolTable.StringToId(text));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<object, object>> IEnumerable<KeyValuePair<object, object>>.GetEnumerator()
|
||||
{
|
||||
bool lockTaken = false;
|
||||
SymbolDictionary obj2 = default(SymbolDictionary);
|
||||
try
|
||||
{
|
||||
SymbolDictionary obj;
|
||||
obj2 = (obj = this);
|
||||
Monitor.Enter(obj, ref lockTaken);
|
||||
foreach (KeyValuePair<SymbolId, object> o in _data)
|
||||
{
|
||||
KeyValuePair<SymbolId, object> keyValuePair = o;
|
||||
if (!(keyValuePair.Key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
KeyValuePair<SymbolId, object> keyValuePair2 = o;
|
||||
string key = SymbolTable.IdToString(keyValuePair2.Key);
|
||||
KeyValuePair<SymbolId, object> keyValuePair3 = o;
|
||||
yield return new KeyValuePair<object, object>(key, keyValuePair3.Value);
|
||||
}
|
||||
}
|
||||
Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
|
||||
if (objData == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (KeyValuePair<object, object> item in objData)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken)
|
||||
{
|
||||
Monitor.Exit(obj2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
foreach (KeyValuePair<SymbolId, object> o in _data)
|
||||
{
|
||||
KeyValuePair<SymbolId, object> keyValuePair = o;
|
||||
if (!(keyValuePair.Key == BaseSymbolDictionary.ObjectKeys))
|
||||
{
|
||||
KeyValuePair<SymbolId, object> keyValuePair2 = o;
|
||||
yield return SymbolTable.IdToString(keyValuePair2.Key);
|
||||
}
|
||||
}
|
||||
IDictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
|
||||
if (objData == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (object key in objData.Keys)
|
||||
{
|
||||
yield return key;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(SymbolId name, object value)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_data.Add(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(SymbolId name)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return _data.ContainsKey(name);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(SymbolId name)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return _data.Remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(SymbolId name, out object value)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return _data.TryGetValue(name, out value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddObjectKey(object name, object value)
|
||||
{
|
||||
AsObjectKeyedDictionary().Add(name, value);
|
||||
}
|
||||
|
||||
public bool ContainsObjectKey(object name)
|
||||
{
|
||||
return AsObjectKeyedDictionary().ContainsKey(name);
|
||||
}
|
||||
|
||||
public bool RemoveObjectKey(object name)
|
||||
{
|
||||
return AsObjectKeyedDictionary().Remove(name);
|
||||
}
|
||||
|
||||
public bool TryGetObjectValue(object name, out object value)
|
||||
{
|
||||
return AsObjectKeyedDictionary().TryGetValue(name, out value);
|
||||
}
|
||||
|
||||
public IDictionary<object, object> AsObjectKeyedDictionary()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void IDictionary.Add(object key, object value)
|
||||
{
|
||||
AsObjectKeyedDictionary().Add(key, value);
|
||||
}
|
||||
|
||||
public bool Contains(object key)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
return AsObjectKeyedDictionary().ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||
{
|
||||
Dictionary<object, object> objectKeysDictionaryIfExists = GetObjectKeysDictionaryIfExists();
|
||||
if (objectKeysDictionaryIfExists == null)
|
||||
{
|
||||
return new TransformDictionaryEnumerator(_data);
|
||||
}
|
||||
List<IDictionaryEnumerator> list = new List<IDictionaryEnumerator>();
|
||||
list.Add(new TransformDictionaryEnumerator(_data));
|
||||
Dictionary<object, object>.Enumerator enumerator = objectKeysDictionaryIfExists.GetEnumerator();
|
||||
list.Add(enumerator);
|
||||
return new DictionaryUnionEnumerator(list);
|
||||
}
|
||||
|
||||
void IDictionary.Remove(object key)
|
||||
{
|
||||
string text = key as string;
|
||||
lock (this)
|
||||
{
|
||||
if (text != null)
|
||||
{
|
||||
_data.Remove(SymbolTable.StringToId(text));
|
||||
}
|
||||
else
|
||||
{
|
||||
GetObjectKeysDictionaryIfExists()?.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
lock (this)
|
||||
{
|
||||
ContractUtils.RequiresListRange(array, index, Count, "index", "array");
|
||||
IEnumerator enumerator = GetEnumerator();
|
||||
try
|
||||
{
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
object current = enumerator.Current;
|
||||
array.SetValue(current, index++);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
IDisposable disposable = enumerator as IDisposable;
|
||||
if (disposable != null)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
AspClassic.Scripting/Runtime/TokenizerService.cs
Normal file
50
AspClassic.Scripting/Runtime/TokenizerService.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
public abstract class TokenizerService
|
||||
{
|
||||
public abstract object CurrentState { get; }
|
||||
|
||||
public abstract SourceLocation CurrentPosition { get; }
|
||||
|
||||
public abstract bool IsRestartable { get; }
|
||||
|
||||
public abstract ErrorSink ErrorSink { get; set; }
|
||||
|
||||
public abstract void Initialize(object state, TextReader sourceReader, SourceUnit sourceUnit, SourceLocation initialLocation);
|
||||
|
||||
public abstract TokenInfo ReadToken();
|
||||
|
||||
public virtual bool SkipToken()
|
||||
{
|
||||
return ReadToken().Category != TokenCategory.EndOfStream;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<TokenInfo> ReadTokens(int countOfChars)
|
||||
{
|
||||
List<TokenInfo> list = new List<TokenInfo>();
|
||||
int index = CurrentPosition.Index;
|
||||
while (CurrentPosition.Index - index < countOfChars)
|
||||
{
|
||||
TokenInfo item = ReadToken();
|
||||
if (item.Category == TokenCategory.EndOfStream)
|
||||
{
|
||||
break;
|
||||
}
|
||||
list.Add(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public bool SkipTokens(int countOfChars)
|
||||
{
|
||||
bool result = false;
|
||||
int index = CurrentPosition.Index;
|
||||
while (CurrentPosition.Index - index < countOfChars && (result = SkipToken()))
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System.Collections.Generic;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Runtime;
|
||||
|
||||
internal class TransformDictionaryEnumerator : CheckedDictionaryEnumerator
|
||||
{
|
||||
private const int ObjectKeysId = -2;
|
||||
|
||||
private IEnumerator<KeyValuePair<SymbolId, object>> _backing;
|
||||
|
||||
internal static readonly SymbolId ObjectKeys = new SymbolId(-2);
|
||||
|
||||
public TransformDictionaryEnumerator(IDictionary<SymbolId, object> backing)
|
||||
{
|
||||
_backing = backing.GetEnumerator();
|
||||
}
|
||||
|
||||
protected override object GetKey()
|
||||
{
|
||||
return SymbolTable.IdToString(_backing.Current.Key);
|
||||
}
|
||||
|
||||
protected override object GetValue()
|
||||
{
|
||||
return _backing.Current.Value;
|
||||
}
|
||||
|
||||
protected override bool DoMoveNext()
|
||||
{
|
||||
bool flag = _backing.MoveNext();
|
||||
if (flag && _backing.Current.Key == ObjectKeys)
|
||||
{
|
||||
flag = MoveNext();
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
protected override void DoReset()
|
||||
{
|
||||
_backing.Reset();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue