progress
This commit is contained in:
parent
16e76d6b31
commit
484dbfc9d9
529 changed files with 113694 additions and 0 deletions
27
AspClassic.Scripting/ArgumentTypeException.cs
Normal file
27
AspClassic.Scripting/ArgumentTypeException.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class ArgumentTypeException : Exception
|
||||
{
|
||||
public ArgumentTypeException()
|
||||
{
|
||||
}
|
||||
|
||||
public ArgumentTypeException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ArgumentTypeException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
protected ArgumentTypeException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
14
AspClassic.Scripting/AspClassic.Scripting.csproj
Normal file
14
AspClassic.Scripting/AspClassic.Scripting.csproj
Normal file
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CodeDom" Version="6.0.0" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
16
AspClassic.Scripting/AssemblyLoadedEventArgs.cs
Normal file
16
AspClassic.Scripting/AssemblyLoadedEventArgs.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public class AssemblyLoadedEventArgs : EventArgs
|
||||
{
|
||||
private Assembly _assembly;
|
||||
|
||||
public Assembly Assembly => _assembly;
|
||||
|
||||
public AssemblyLoadedEventArgs(Assembly assembly)
|
||||
{
|
||||
_assembly = assembly;
|
||||
}
|
||||
}
|
12
AspClassic.Scripting/CompilerOptions.cs
Normal file
12
AspClassic.Scripting/CompilerOptions.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class CompilerOptions : ICloneable
|
||||
{
|
||||
public virtual object Clone()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
}
|
277
AspClassic.Scripting/Error.cs
Normal file
277
AspClassic.Scripting/Error.cs
Normal file
|
@ -0,0 +1,277 @@
|
|||
using System;
|
||||
using System.Security;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
internal static class Error
|
||||
{
|
||||
internal static Exception MustHaveCodeOrTarget()
|
||||
{
|
||||
return new ArgumentException(Strings.MustHaveCodeOrTarget);
|
||||
}
|
||||
|
||||
internal static Exception TypeParameterIsNotDelegate(object p0)
|
||||
{
|
||||
return new InvalidOperationException(Strings.TypeParameterIsNotDelegate(p0));
|
||||
}
|
||||
|
||||
internal static Exception InvalidCast(object p0, object p1)
|
||||
{
|
||||
return new InvalidOperationException(Strings.InvalidCast(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception UnknownMemberType(object p0)
|
||||
{
|
||||
return new InvalidOperationException(Strings.UnknownMemberType(p0));
|
||||
}
|
||||
|
||||
internal static Exception FirstArgumentMustBeCallSite()
|
||||
{
|
||||
return new InvalidOperationException(Strings.FirstArgumentMustBeCallSite);
|
||||
}
|
||||
|
||||
internal static Exception NoInstanceForCall()
|
||||
{
|
||||
return new InvalidOperationException(Strings.NoInstanceForCall);
|
||||
}
|
||||
|
||||
internal static Exception MissingTest()
|
||||
{
|
||||
return new InvalidOperationException(Strings.MissingTest);
|
||||
}
|
||||
|
||||
internal static Exception MissingTarget()
|
||||
{
|
||||
return new InvalidOperationException(Strings.MissingTarget);
|
||||
}
|
||||
|
||||
internal static Exception NonGenericWithGenericGroup(object p0)
|
||||
{
|
||||
return new TypeLoadException(Strings.NonGenericWithGenericGroup(p0));
|
||||
}
|
||||
|
||||
internal static Exception InvalidOperation(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidOperation(p0));
|
||||
}
|
||||
|
||||
internal static Exception FinallyAlreadyDefined()
|
||||
{
|
||||
return new InvalidOperationException(Strings.FinallyAlreadyDefined);
|
||||
}
|
||||
|
||||
internal static Exception CannotHaveFaultAndFinally()
|
||||
{
|
||||
return new InvalidOperationException(Strings.CannotHaveFaultAndFinally);
|
||||
}
|
||||
|
||||
internal static Exception FaultAlreadyDefined()
|
||||
{
|
||||
return new InvalidOperationException(Strings.FaultAlreadyDefined);
|
||||
}
|
||||
|
||||
internal static Exception CantCreateDefaultTypeFor(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.CantCreateDefaultTypeFor(p0));
|
||||
}
|
||||
|
||||
internal static Exception UnhandledConvert(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.UnhandledConvert(p0));
|
||||
}
|
||||
|
||||
internal static Exception NoCallableMethods(object p0, object p1)
|
||||
{
|
||||
return new InvalidOperationException(Strings.NoCallableMethods(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception GlobalsMustBeUnique()
|
||||
{
|
||||
return new ArgumentException(Strings.GlobalsMustBeUnique);
|
||||
}
|
||||
|
||||
internal static Exception GenNonSerializableBinder()
|
||||
{
|
||||
return new ArgumentException(Strings.GenNonSerializableBinder);
|
||||
}
|
||||
|
||||
internal static Exception InvalidPath()
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidPath);
|
||||
}
|
||||
|
||||
internal static Exception DictionaryNotHashable()
|
||||
{
|
||||
return new ArgumentTypeException(Strings.DictionaryNotHashable);
|
||||
}
|
||||
|
||||
internal static Exception LanguageRegistered()
|
||||
{
|
||||
return new InvalidOperationException(Strings.LanguageRegistered);
|
||||
}
|
||||
|
||||
internal static Exception MethodOrOperatorNotImplemented()
|
||||
{
|
||||
return new NotImplementedException(Strings.MethodOrOperatorNotImplemented);
|
||||
}
|
||||
|
||||
internal static Exception NoException()
|
||||
{
|
||||
return new InvalidOperationException(Strings.NoException);
|
||||
}
|
||||
|
||||
internal static Exception ExtensionMustBePublic(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.ExtensionMustBePublic(p0));
|
||||
}
|
||||
|
||||
internal static Exception AlreadyInitialized()
|
||||
{
|
||||
return new InvalidOperationException(Strings.AlreadyInitialized);
|
||||
}
|
||||
|
||||
internal static Exception MustReturnScopeExtension()
|
||||
{
|
||||
return new InvalidImplementationException(Strings.MustReturnScopeExtension);
|
||||
}
|
||||
|
||||
internal static Exception InvalidParamNumForService()
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidParamNumForService);
|
||||
}
|
||||
|
||||
internal static Exception InvalidArgumentType(object p0, object p1)
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidArgumentType(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception CannotChangeNonCachingValue()
|
||||
{
|
||||
return new ArgumentException(Strings.CannotChangeNonCachingValue);
|
||||
}
|
||||
|
||||
internal static Exception FieldReadonly(object p0)
|
||||
{
|
||||
return new MissingMemberException(Strings.FieldReadonly(p0));
|
||||
}
|
||||
|
||||
internal static Exception PropertyReadonly(object p0)
|
||||
{
|
||||
return new MissingMemberException(Strings.PropertyReadonly(p0));
|
||||
}
|
||||
|
||||
internal static Exception UnexpectedEvent(object p0, object p1, object p2, object p3)
|
||||
{
|
||||
return new ArgumentException(Strings.UnexpectedEvent(p0, p1, p2, p3));
|
||||
}
|
||||
|
||||
internal static Exception ExpectedBoundEvent(object p0)
|
||||
{
|
||||
return new ArgumentTypeException(Strings.ExpectedBoundEvent(p0));
|
||||
}
|
||||
|
||||
internal static Exception UnexpectedType(object p0, object p1)
|
||||
{
|
||||
return new ArgumentTypeException(Strings.UnexpectedType(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception MemberWriteOnly(object p0)
|
||||
{
|
||||
return new MemberAccessException(Strings.MemberWriteOnly(p0));
|
||||
}
|
||||
|
||||
internal static Exception NoCodeToCompile()
|
||||
{
|
||||
return new InvalidOperationException(Strings.NoCodeToCompile);
|
||||
}
|
||||
|
||||
internal static Exception InvalidStreamType(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidStreamType(p0));
|
||||
}
|
||||
|
||||
internal static Exception QueueEmpty()
|
||||
{
|
||||
return new InvalidOperationException(Strings.QueueEmpty);
|
||||
}
|
||||
|
||||
internal static Exception EnumerationNotStarted()
|
||||
{
|
||||
return new InvalidOperationException(Strings.EnumerationNotStarted);
|
||||
}
|
||||
|
||||
internal static Exception EnumerationFinished()
|
||||
{
|
||||
return new InvalidOperationException(Strings.EnumerationFinished);
|
||||
}
|
||||
|
||||
internal static Exception CantAddCasing(object p0)
|
||||
{
|
||||
return new InvalidOperationException(Strings.CantAddCasing(p0));
|
||||
}
|
||||
|
||||
internal static Exception CantAddIdentifier(object p0)
|
||||
{
|
||||
return new InvalidOperationException(Strings.CantAddIdentifier(p0));
|
||||
}
|
||||
|
||||
internal static Exception InvalidOutputDir()
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidOutputDir);
|
||||
}
|
||||
|
||||
internal static Exception InvalidAsmNameOrExtension()
|
||||
{
|
||||
return new ArgumentException(Strings.InvalidAsmNameOrExtension);
|
||||
}
|
||||
|
||||
internal static Exception CanotEmitConstant(object p0, object p1)
|
||||
{
|
||||
return new ArgumentException(Strings.CanotEmitConstant(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception NoImplicitCast(object p0, object p1)
|
||||
{
|
||||
return new ArgumentException(Strings.NoImplicitCast(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception NoExplicitCast(object p0, object p1)
|
||||
{
|
||||
return new ArgumentException(Strings.NoExplicitCast(p0, p1));
|
||||
}
|
||||
|
||||
internal static Exception NameNotDefined(object p0)
|
||||
{
|
||||
return new MissingMemberException(Strings.NameNotDefined(p0));
|
||||
}
|
||||
|
||||
internal static Exception NoDefaultValue()
|
||||
{
|
||||
return new ArgumentException(Strings.NoDefaultValue);
|
||||
}
|
||||
|
||||
internal static Exception UnknownLanguageProviderType()
|
||||
{
|
||||
return new ArgumentException(Strings.UnknownLanguageProviderType);
|
||||
}
|
||||
|
||||
internal static Exception CantReadProperty()
|
||||
{
|
||||
return new InvalidOperationException(Strings.CantReadProperty);
|
||||
}
|
||||
|
||||
internal static Exception CantWriteProperty()
|
||||
{
|
||||
return new InvalidOperationException(Strings.CantWriteProperty);
|
||||
}
|
||||
|
||||
internal static Exception IllegalNew_GenericParams(object p0)
|
||||
{
|
||||
return new ArgumentException(Strings.IllegalNew_GenericParams(p0));
|
||||
}
|
||||
|
||||
internal static Exception VerificationException(object p0, object p1, object p2)
|
||||
{
|
||||
return new VerificationException(Strings.VerificationException(p0, p1, p2));
|
||||
}
|
||||
}
|
71
AspClassic.Scripting/ErrorCounter.cs
Normal file
71
AspClassic.Scripting/ErrorCounter.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public class ErrorCounter : ErrorSink
|
||||
{
|
||||
private readonly ErrorSink _sink;
|
||||
|
||||
private int _fatalErrorCount;
|
||||
|
||||
private int _errorCount;
|
||||
|
||||
private int _warningCount;
|
||||
|
||||
public int FatalErrorCount => _fatalErrorCount;
|
||||
|
||||
public int ErrorCount => _errorCount;
|
||||
|
||||
public int WarningCount => _warningCount;
|
||||
|
||||
public bool AnyError
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_errorCount <= 0)
|
||||
{
|
||||
return _fatalErrorCount > 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public ErrorCounter()
|
||||
: this(ErrorSink.Null)
|
||||
{
|
||||
}
|
||||
|
||||
public ErrorCounter(ErrorSink sink)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(sink, "sink");
|
||||
_sink = sink;
|
||||
}
|
||||
|
||||
protected virtual void CountError(Severity severity)
|
||||
{
|
||||
switch (severity)
|
||||
{
|
||||
case Severity.FatalError:
|
||||
Interlocked.Increment(ref _fatalErrorCount);
|
||||
break;
|
||||
case Severity.Error:
|
||||
Interlocked.Increment(ref _errorCount);
|
||||
break;
|
||||
case Severity.Warning:
|
||||
Interlocked.Increment(ref _warningCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearCounters()
|
||||
{
|
||||
_warningCount = (_errorCount = (_fatalErrorCount = 0));
|
||||
}
|
||||
|
||||
public override void Add(SourceUnit source, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
CountError(severity);
|
||||
_sink.Add(source, message, span, errorCode, severity);
|
||||
}
|
||||
}
|
28
AspClassic.Scripting/ErrorSink.cs
Normal file
28
AspClassic.Scripting/ErrorSink.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public class ErrorSink
|
||||
{
|
||||
public static readonly ErrorSink Default = new ErrorSink();
|
||||
|
||||
public static readonly ErrorSink Null = new NullErrorSink();
|
||||
|
||||
protected ErrorSink()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Add(SourceUnit source, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
if (severity == Severity.FatalError || severity == Severity.Error)
|
||||
{
|
||||
throw new SyntaxErrorException(message, source, span, errorCode, severity);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Add(string message, string path, string code, string line, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
if (severity == Severity.FatalError || severity == Severity.Error)
|
||||
{
|
||||
throw new SyntaxErrorException(message, path, code, line, span, errorCode, severity);
|
||||
}
|
||||
}
|
||||
}
|
49
AspClassic.Scripting/FileStreamContentProvider.cs
Normal file
49
AspClassic.Scripting/FileStreamContentProvider.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
internal sealed class FileStreamContentProvider : StreamContentProvider
|
||||
{
|
||||
[Serializable]
|
||||
private class PALHolder : MarshalByRefObject
|
||||
{
|
||||
[NonSerialized]
|
||||
private readonly PlatformAdaptationLayer _pal;
|
||||
|
||||
internal PALHolder(PlatformAdaptationLayer pal)
|
||||
{
|
||||
_pal = pal;
|
||||
}
|
||||
|
||||
internal Stream GetStream(string path)
|
||||
{
|
||||
return _pal.OpenInputFileStream(path);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly string _path;
|
||||
|
||||
private readonly PALHolder _pal;
|
||||
|
||||
internal string Path => _path;
|
||||
|
||||
internal FileStreamContentProvider(PlatformAdaptationLayer pal, string path)
|
||||
{
|
||||
_path = path;
|
||||
_pal = new PALHolder(pal);
|
||||
}
|
||||
|
||||
public override Stream GetStream()
|
||||
{
|
||||
return _pal.GetStream(Path);
|
||||
}
|
||||
}
|
103
AspClassic.Scripting/Hosting/CompiledCode.cs
Normal file
103
AspClassic.Scripting/Hosting/CompiledCode.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class CompiledCode : MarshalByRefObject
|
||||
{
|
||||
private readonly ScriptEngine _engine;
|
||||
|
||||
private readonly ScriptCode _code;
|
||||
|
||||
private ScriptScope _defaultScope;
|
||||
|
||||
internal ScriptCode ScriptCode => _code;
|
||||
|
||||
public ScriptEngine Engine => _engine;
|
||||
|
||||
public ScriptScope DefaultScope
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultScope == null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _defaultScope, new ScriptScope(_engine, _code.CreateScope()), null);
|
||||
}
|
||||
return _defaultScope;
|
||||
}
|
||||
}
|
||||
|
||||
internal CompiledCode(ScriptEngine engine, ScriptCode code)
|
||||
{
|
||||
_engine = engine;
|
||||
_code = code;
|
||||
}
|
||||
|
||||
public dynamic Execute()
|
||||
{
|
||||
return _code.Run(DefaultScope.Scope);
|
||||
}
|
||||
|
||||
public dynamic Execute(ScriptScope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
return _code.Run(scope.Scope);
|
||||
}
|
||||
|
||||
public T Execute<T>()
|
||||
{
|
||||
return _engine.Operations.ConvertTo<T>((object)Execute());
|
||||
}
|
||||
|
||||
public T Execute<T>(ScriptScope scope)
|
||||
{
|
||||
return _engine.Operations.ConvertTo<T>((object)Execute(scope));
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap()
|
||||
{
|
||||
return new ObjectHandle((object)Execute());
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(ScriptScope scope)
|
||||
{
|
||||
return new ObjectHandle((object)Execute(scope));
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(out ObjectHandle exception)
|
||||
{
|
||||
exception = null;
|
||||
try
|
||||
{
|
||||
return new ObjectHandle((object)Execute());
|
||||
}
|
||||
catch (Exception o)
|
||||
{
|
||||
exception = new ObjectHandle(o);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(ScriptScope scope, out ObjectHandle exception)
|
||||
{
|
||||
exception = null;
|
||||
try
|
||||
{
|
||||
return new ObjectHandle((object)Execute(scope));
|
||||
}
|
||||
catch (Exception o)
|
||||
{
|
||||
exception = new ObjectHandle(o);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
using System.Configuration;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Configuration;
|
||||
|
||||
public class LanguageElement : ConfigurationElement
|
||||
{
|
||||
private const string _Names = "names";
|
||||
|
||||
private const string _Extensions = "extensions";
|
||||
|
||||
private const string _Type = "type";
|
||||
|
||||
private const string _DisplayName = "displayName";
|
||||
|
||||
private static ConfigurationPropertyCollection _Properties = new ConfigurationPropertyCollection
|
||||
{
|
||||
new ConfigurationProperty("names", typeof(string), null),
|
||||
new ConfigurationProperty("extensions", typeof(string), null),
|
||||
new ConfigurationProperty("type", typeof(string), null, ConfigurationPropertyOptions.IsRequired),
|
||||
new ConfigurationProperty("displayName", typeof(string), null)
|
||||
};
|
||||
|
||||
protected override ConfigurationPropertyCollection Properties => _Properties;
|
||||
|
||||
public string Names
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["names"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["names"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Extensions
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["extensions"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["extensions"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["type"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["type"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["displayName"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["displayName"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] GetNamesArray()
|
||||
{
|
||||
return Split(Names);
|
||||
}
|
||||
|
||||
public string[] GetExtensionsArray()
|
||||
{
|
||||
return Split(Extensions);
|
||||
}
|
||||
|
||||
private static string[] Split(string str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return ArrayUtils.EmptyStrings;
|
||||
}
|
||||
return str.Split(new char[2] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System.Configuration;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Configuration;
|
||||
|
||||
public class LanguageElementCollection : ConfigurationElementCollection
|
||||
{
|
||||
public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.BasicMap;
|
||||
|
||||
protected override bool ThrowOnDuplicate => false;
|
||||
|
||||
protected override string ElementName => "language";
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new LanguageElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((LanguageElement)element).Type;
|
||||
}
|
||||
}
|
105
AspClassic.Scripting/Hosting/Configuration/OptionElement.cs
Normal file
105
AspClassic.Scripting/Hosting/Configuration/OptionElement.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Configuration;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Configuration;
|
||||
|
||||
public class OptionElement : ConfigurationElement
|
||||
{
|
||||
internal sealed class Key : IEquatable<Key>
|
||||
{
|
||||
private readonly string _option;
|
||||
|
||||
private readonly string _language;
|
||||
|
||||
public string Option => _option;
|
||||
|
||||
public string Language => _language;
|
||||
|
||||
public Key(string option, string language)
|
||||
{
|
||||
_option = option;
|
||||
_language = language;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as Key);
|
||||
}
|
||||
|
||||
public bool Equals(Key other)
|
||||
{
|
||||
if (other != null && DlrConfiguration.OptionNameComparer.Equals(_option, other._option))
|
||||
{
|
||||
return DlrConfiguration.LanguageNameComparer.Equals(_language, other._language);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _option.GetHashCode() ^ (_language ?? string.Empty).GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return (string.IsNullOrEmpty(_language) ? string.Empty : (_language + ":")) + _option;
|
||||
}
|
||||
}
|
||||
|
||||
private const string _Option = "option";
|
||||
|
||||
private const string _Value = "value";
|
||||
|
||||
private const string _Language = "language";
|
||||
|
||||
private static ConfigurationPropertyCollection _Properties = new ConfigurationPropertyCollection
|
||||
{
|
||||
new ConfigurationProperty("option", typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsKey),
|
||||
new ConfigurationProperty("value", typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired),
|
||||
new ConfigurationProperty("language", typeof(string), string.Empty, ConfigurationPropertyOptions.IsKey)
|
||||
};
|
||||
|
||||
protected override ConfigurationPropertyCollection Properties => _Properties;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["option"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["option"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["value"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["value"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Language
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base["language"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["language"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal object GetKey()
|
||||
{
|
||||
return new Key(Name, Language);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.Configuration;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Configuration;
|
||||
|
||||
public class OptionElementCollection : ConfigurationElementCollection
|
||||
{
|
||||
public override ConfigurationElementCollectionType CollectionType => ConfigurationElementCollectionType.AddRemoveClearMap;
|
||||
|
||||
protected override bool ThrowOnDuplicate => false;
|
||||
|
||||
public OptionElementCollection()
|
||||
{
|
||||
base.AddElementName = "set";
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new OptionElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((OptionElement)element).GetKey();
|
||||
}
|
||||
}
|
166
AspClassic.Scripting/Hosting/Configuration/Section.cs
Normal file
166
AspClassic.Scripting/Hosting/Configuration/Section.cs
Normal file
|
@ -0,0 +1,166 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Configuration;
|
||||
|
||||
public class Section : ConfigurationSection
|
||||
{
|
||||
private const string _DebugMode = "debugMode";
|
||||
|
||||
private const string _PrivateBinding = "privateBinding";
|
||||
|
||||
private const string _Languages = "languages";
|
||||
|
||||
private const string _Options = "options";
|
||||
|
||||
public static readonly string SectionName = "AspClassic.Scripting";
|
||||
|
||||
private static ConfigurationPropertyCollection _Properties = new ConfigurationPropertyCollection
|
||||
{
|
||||
new ConfigurationProperty("debugMode", typeof(bool?), null),
|
||||
new ConfigurationProperty("privateBinding", typeof(bool?), null),
|
||||
new ConfigurationProperty("languages", typeof(LanguageElementCollection), null, ConfigurationPropertyOptions.IsDefaultCollection),
|
||||
new ConfigurationProperty("options", typeof(OptionElementCollection), null)
|
||||
};
|
||||
|
||||
protected override ConfigurationPropertyCollection Properties => _Properties;
|
||||
|
||||
public bool? DebugMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool?)base["debugMode"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["debugMode"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool? PrivateBinding
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool?)base["privateBinding"];
|
||||
}
|
||||
set
|
||||
{
|
||||
base["privateBinding"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<LanguageElement> GetLanguages()
|
||||
{
|
||||
if (!(base["languages"] is LanguageElementCollection languages))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (object languageConfig in languages)
|
||||
{
|
||||
yield return (LanguageElement)languageConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<OptionElement> GetOptions()
|
||||
{
|
||||
if (!(base["options"] is OptionElementCollection options))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (object option in options)
|
||||
{
|
||||
yield return (OptionElement)option;
|
||||
}
|
||||
}
|
||||
|
||||
private static Section LoadFromFile(Stream configFileStream)
|
||||
{
|
||||
Section section = new Section();
|
||||
using XmlReader xmlReader = XmlReader.Create(configFileStream);
|
||||
if (xmlReader.ReadToDescendant("configuration") && xmlReader.ReadToDescendant(SectionName))
|
||||
{
|
||||
section.DeserializeElement(xmlReader, serializeCollectionKey: false);
|
||||
return section;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void LoadRuntimeSetup(ScriptRuntimeSetup setup, Stream configFileStream)
|
||||
{
|
||||
Section section = ((configFileStream == null) ? (ConfigurationManager.GetSection(SectionName) as Section) : LoadFromFile(configFileStream));
|
||||
if (section == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (section.DebugMode.HasValue)
|
||||
{
|
||||
setup.DebugMode = section.DebugMode.Value;
|
||||
}
|
||||
if (section.PrivateBinding.HasValue)
|
||||
{
|
||||
setup.PrivateBinding = section.PrivateBinding.Value;
|
||||
}
|
||||
foreach (LanguageElement language in section.GetLanguages())
|
||||
{
|
||||
string type = language.Type;
|
||||
string[] namesArray = language.GetNamesArray();
|
||||
string[] extensionsArray = language.GetExtensionsArray();
|
||||
string displayName = language.DisplayName ?? ((namesArray.Length > 0) ? namesArray[0] : language.Type);
|
||||
bool flag = false;
|
||||
foreach (LanguageSetup languageSetup in setup.LanguageSetups)
|
||||
{
|
||||
if (languageSetup.TypeName == type)
|
||||
{
|
||||
languageSetup.Names.Clear();
|
||||
string[] array = namesArray;
|
||||
foreach (string item in array)
|
||||
{
|
||||
languageSetup.Names.Add(item);
|
||||
}
|
||||
languageSetup.FileExtensions.Clear();
|
||||
string[] array2 = extensionsArray;
|
||||
foreach (string item2 in array2)
|
||||
{
|
||||
languageSetup.FileExtensions.Add(item2);
|
||||
}
|
||||
languageSetup.DisplayName = displayName;
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
setup.LanguageSetups.Add(new LanguageSetup(type, displayName, namesArray, extensionsArray));
|
||||
}
|
||||
}
|
||||
OptionElement option;
|
||||
foreach (OptionElement option2 in section.GetOptions())
|
||||
{
|
||||
option = option2;
|
||||
if (string.IsNullOrEmpty(option.Language))
|
||||
{
|
||||
setup.Options[option.Name] = option.Value;
|
||||
continue;
|
||||
}
|
||||
bool flag2 = false;
|
||||
foreach (LanguageSetup languageSetup2 in setup.LanguageSetups)
|
||||
{
|
||||
if (Utils.CollectionExtensions.Any(languageSetup2.Names,(string s) => DlrConfiguration.LanguageNameComparer.Equals(s, option.Language)))
|
||||
{
|
||||
languageSetup2.Options[option.Name] = option.Value;
|
||||
flag2 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
throw new ConfigurationErrorsException($"Unknown language name: '{option.Language}'");
|
||||
}
|
||||
}
|
||||
}
|
43
AspClassic.Scripting/Hosting/DocumentationOperations.cs
Normal file
43
AspClassic.Scripting/Hosting/DocumentationOperations.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class DocumentationOperations : MarshalByRefObject
|
||||
{
|
||||
private readonly DocumentationProvider _provider;
|
||||
|
||||
internal DocumentationOperations(DocumentationProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public ICollection<MemberDoc> GetMembers(object value)
|
||||
{
|
||||
return _provider.GetMembers(value);
|
||||
}
|
||||
|
||||
public ICollection<OverloadDoc> GetOverloads(object value)
|
||||
{
|
||||
return _provider.GetOverloads(value);
|
||||
}
|
||||
|
||||
public ICollection<MemberDoc> GetMembers(ObjectHandle value)
|
||||
{
|
||||
return _provider.GetMembers(value.Unwrap());
|
||||
}
|
||||
|
||||
public ICollection<OverloadDoc> GetOverloads(ObjectHandle value)
|
||||
{
|
||||
return _provider.GetOverloads(value.Unwrap());
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
20
AspClassic.Scripting/Hosting/ErrorListener.cs
Normal file
20
AspClassic.Scripting/Hosting/ErrorListener.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public abstract class ErrorListener : MarshalByRefObject
|
||||
{
|
||||
internal void ReportError(ScriptSource source, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
ErrorReported(source, message, span, errorCode, severity);
|
||||
}
|
||||
|
||||
public abstract void ErrorReported(ScriptSource source, string message, SourceSpan span, int errorCode, Severity severity);
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
27
AspClassic.Scripting/Hosting/ErrorListenerProxySink.cs
Normal file
27
AspClassic.Scripting/Hosting/ErrorListenerProxySink.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
internal sealed class ErrorListenerProxySink : ErrorSink
|
||||
{
|
||||
private readonly ErrorListener _listener;
|
||||
|
||||
private readonly ScriptSource _source;
|
||||
|
||||
public ErrorListenerProxySink(ScriptSource source, ErrorListener listener)
|
||||
{
|
||||
_listener = listener;
|
||||
_source = source;
|
||||
}
|
||||
|
||||
public override void Add(SourceUnit sourceUnit, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
if (_listener != null)
|
||||
{
|
||||
ScriptSource source = ((sourceUnit == _source.SourceUnit) ? _source : new ScriptSource(_source.Engine.Runtime.GetEngine(sourceUnit.LanguageContext), sourceUnit));
|
||||
_listener.ErrorReported(source, message, span, errorCode, severity);
|
||||
}
|
||||
else if (severity == Severity.FatalError || severity == Severity.Error)
|
||||
{
|
||||
throw new SyntaxErrorException(message, sourceUnit, span, errorCode, severity);
|
||||
}
|
||||
}
|
||||
}
|
28
AspClassic.Scripting/Hosting/ErrorSinkProxyListener.cs
Normal file
28
AspClassic.Scripting/Hosting/ErrorSinkProxyListener.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.IO;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class ErrorSinkProxyListener : ErrorListener
|
||||
{
|
||||
private ErrorSink _errorSink;
|
||||
|
||||
public ErrorSinkProxyListener(ErrorSink errorSink)
|
||||
{
|
||||
_errorSink = errorSink;
|
||||
}
|
||||
|
||||
public override void ErrorReported(ScriptSource source, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
string code = null;
|
||||
string line = null;
|
||||
try
|
||||
{
|
||||
code = source.GetCode();
|
||||
line = source.GetCodeLine(span.Start.Line);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
_errorSink.Add(message, source.Path, code, line, span, errorCode, severity);
|
||||
}
|
||||
}
|
61
AspClassic.Scripting/Hosting/ExceptionOperations.cs
Normal file
61
AspClassic.Scripting/Hosting/ExceptionOperations.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class ExceptionOperations : MarshalByRefObject
|
||||
{
|
||||
private readonly LanguageContext _context;
|
||||
|
||||
internal ExceptionOperations(LanguageContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public string FormatException(Exception exception)
|
||||
{
|
||||
return _context.FormatException(exception);
|
||||
}
|
||||
|
||||
public void GetExceptionMessage(Exception exception, out string message, out string errorTypeName)
|
||||
{
|
||||
_context.GetExceptionMessage(exception, out message, out errorTypeName);
|
||||
}
|
||||
|
||||
public bool HandleException(Exception exception)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(exception, "exception");
|
||||
return false;
|
||||
}
|
||||
|
||||
public string FormatException(ObjectHandle exception)
|
||||
{
|
||||
Exception ex = exception.Unwrap() as Exception;
|
||||
ContractUtils.Requires(ex != null, "exception", "ObjectHandle must be to Exception object");
|
||||
return _context.FormatException(ex);
|
||||
}
|
||||
|
||||
public void GetExceptionMessage(ObjectHandle exception, out string message, out string errorTypeName)
|
||||
{
|
||||
Exception ex = exception.Unwrap() as Exception;
|
||||
ContractUtils.Requires(ex != null, "exception", "ObjectHandle must be to Exception object");
|
||||
_context.GetExceptionMessage(ex, out message, out errorTypeName);
|
||||
}
|
||||
|
||||
public bool HandleException(ObjectHandle exception)
|
||||
{
|
||||
Exception ex = exception.Unwrap() as Exception;
|
||||
ContractUtils.Requires(ex != null, "exception", "ObjectHandle must be to Exception object");
|
||||
ContractUtils.RequiresNotNull(ex, "exception");
|
||||
return false;
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
186
AspClassic.Scripting/Hosting/LanguageSetup.cs
Normal file
186
AspClassic.Scripting/Hosting/LanguageSetup.cs
Normal file
|
@ -0,0 +1,186 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Serializable]
|
||||
public sealed class LanguageSetup
|
||||
{
|
||||
private string _typeName;
|
||||
|
||||
private string _displayName;
|
||||
|
||||
private IList<string> _names;
|
||||
|
||||
private IList<string> _fileExtensions;
|
||||
|
||||
private IDictionary<string, object> _options;
|
||||
|
||||
private bool _frozen;
|
||||
|
||||
private bool? _interpretedMode;
|
||||
|
||||
private bool? _exceptionDetail;
|
||||
|
||||
private bool? _perfStats;
|
||||
|
||||
private bool? _noAdaptiveCompilation;
|
||||
|
||||
public string TypeName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _typeName;
|
||||
}
|
||||
set
|
||||
{
|
||||
ContractUtils.RequiresNotEmpty(value, "value");
|
||||
CheckFrozen();
|
||||
_typeName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _displayName;
|
||||
}
|
||||
set
|
||||
{
|
||||
ContractUtils.RequiresNotNull(value, "value");
|
||||
CheckFrozen();
|
||||
_displayName = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<string> Names => _names;
|
||||
|
||||
public IList<string> FileExtensions => _fileExtensions;
|
||||
|
||||
public IDictionary<string, object> Options => _options;
|
||||
|
||||
[Obsolete("This option is ignored")]
|
||||
public bool InterpretedMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCachedOption("InterpretedMode", ref _interpretedMode);
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
Options["InterpretedMode"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use Options[\"NoAdaptiveCompilation\"] instead.")]
|
||||
public bool NoAdaptiveCompilation
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCachedOption("NoAdaptiveCompilation", ref _noAdaptiveCompilation);
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
Options["NoAdaptiveCompilation"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ExceptionDetail
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCachedOption("ExceptionDetail", ref _exceptionDetail);
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
Options["ExceptionDetail"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use Options[\"PerfStats\"] instead.")]
|
||||
public bool PerfStats
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetCachedOption("PerfStats", ref _perfStats);
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
Options["PerfStats"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageSetup(string typeName)
|
||||
: this(typeName, "", ArrayUtils.EmptyStrings, ArrayUtils.EmptyStrings)
|
||||
{
|
||||
}
|
||||
|
||||
public LanguageSetup(string typeName, string displayName)
|
||||
: this(typeName, displayName, ArrayUtils.EmptyStrings, ArrayUtils.EmptyStrings)
|
||||
{
|
||||
}
|
||||
|
||||
public LanguageSetup(string typeName, string displayName, IEnumerable<string> names, IEnumerable<string> fileExtensions)
|
||||
{
|
||||
ContractUtils.RequiresNotEmpty(typeName, "typeName");
|
||||
ContractUtils.RequiresNotNull(displayName, "displayName");
|
||||
ContractUtils.RequiresNotNull(names, "names");
|
||||
ContractUtils.RequiresNotNull(fileExtensions, "fileExtensions");
|
||||
_typeName = typeName;
|
||||
_displayName = displayName;
|
||||
_names = new List<string>(names);
|
||||
_fileExtensions = new List<string>(fileExtensions);
|
||||
_options = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
public T GetOption<T>(string name, T defaultValue)
|
||||
{
|
||||
if (_options != null && _options.TryGetValue(name, out var value))
|
||||
{
|
||||
if (value is T)
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
return (T)Convert.ChangeType(value, typeof(T), Thread.CurrentThread.CurrentCulture);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private bool GetCachedOption(string name, ref bool? storage)
|
||||
{
|
||||
if (storage.HasValue)
|
||||
{
|
||||
return storage.Value;
|
||||
}
|
||||
if (_frozen)
|
||||
{
|
||||
storage = GetOption(name, defaultValue: false);
|
||||
return storage.Value;
|
||||
}
|
||||
return GetOption(name, defaultValue: false);
|
||||
}
|
||||
|
||||
internal void Freeze()
|
||||
{
|
||||
_frozen = true;
|
||||
_names = new ReadOnlyCollection<string>(ArrayUtils.MakeArray(_names));
|
||||
_fileExtensions = new ReadOnlyCollection<string>(ArrayUtils.MakeArray(_fileExtensions));
|
||||
_options = new AspClassic.Scripting.Utils.ReadOnlyDictionary<string, object>(new Dictionary<string, object>(_options));
|
||||
}
|
||||
|
||||
private void CheckFrozen()
|
||||
{
|
||||
if (_frozen)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot modify LanguageSetup after it has been used to create a ScriptRuntime");
|
||||
}
|
||||
}
|
||||
}
|
24
AspClassic.Scripting/Hosting/MemberDoc.cs
Normal file
24
AspClassic.Scripting/Hosting/MemberDoc.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Serializable]
|
||||
public class MemberDoc
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
private readonly MemberKind _kind;
|
||||
|
||||
public string Name => _name;
|
||||
|
||||
public MemberKind Kind => _kind;
|
||||
|
||||
public MemberDoc(string name, MemberKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
ContractUtils.Requires(kind >= MemberKind.None && kind <= MemberKind.Namespace, "kind");
|
||||
_name = name;
|
||||
_kind = kind;
|
||||
}
|
||||
}
|
19
AspClassic.Scripting/Hosting/MemberKind.cs
Normal file
19
AspClassic.Scripting/Hosting/MemberKind.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public enum MemberKind
|
||||
{
|
||||
None,
|
||||
Class,
|
||||
Delegate,
|
||||
Enum,
|
||||
Event,
|
||||
Field,
|
||||
Function,
|
||||
Module,
|
||||
Property,
|
||||
Constant,
|
||||
EnumMember,
|
||||
Instance,
|
||||
Method,
|
||||
Namespace
|
||||
}
|
741
AspClassic.Scripting/Hosting/ObjectOperations.cs
Normal file
741
AspClassic.Scripting/Hosting/ObjectOperations.cs
Normal file
|
@ -0,0 +1,741 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class ObjectOperations : MarshalByRefObject
|
||||
{
|
||||
private readonly DynamicOperations _ops;
|
||||
|
||||
private readonly ScriptEngine _engine;
|
||||
|
||||
public ScriptEngine Engine => _engine;
|
||||
|
||||
internal ObjectOperations(DynamicOperations ops, ScriptEngine engine)
|
||||
{
|
||||
_ops = ops;
|
||||
_engine = engine;
|
||||
}
|
||||
|
||||
public bool IsCallable(object obj)
|
||||
{
|
||||
return _ops.IsCallable(obj);
|
||||
}
|
||||
|
||||
public dynamic Invoke(object obj, params object[] parameters)
|
||||
{
|
||||
return _ops.Invoke(obj, parameters);
|
||||
}
|
||||
|
||||
public dynamic InvokeMember(object obj, string memberName, params object[] parameters)
|
||||
{
|
||||
return _ops.InvokeMember(obj, memberName, parameters);
|
||||
}
|
||||
|
||||
public dynamic CreateInstance(object obj, params object[] parameters)
|
||||
{
|
||||
return _ops.CreateInstance(obj, parameters);
|
||||
}
|
||||
|
||||
public dynamic GetMember(object obj, string name)
|
||||
{
|
||||
return _ops.GetMember(obj, name);
|
||||
}
|
||||
|
||||
public T GetMember<T>(object obj, string name)
|
||||
{
|
||||
return _ops.GetMember<T>(obj, name);
|
||||
}
|
||||
|
||||
public bool TryGetMember(object obj, string name, out object value)
|
||||
{
|
||||
return _ops.TryGetMember(obj, name, out value);
|
||||
}
|
||||
|
||||
public bool ContainsMember(object obj, string name)
|
||||
{
|
||||
return _ops.ContainsMember(obj, name);
|
||||
}
|
||||
|
||||
public void RemoveMember(object obj, string name)
|
||||
{
|
||||
_ops.RemoveMember(obj, name);
|
||||
}
|
||||
|
||||
public void SetMember(object obj, string name, object value)
|
||||
{
|
||||
_ops.SetMember(obj, name, value);
|
||||
}
|
||||
|
||||
public void SetMember<T>(object obj, string name, T value)
|
||||
{
|
||||
_ops.SetMember(obj, name, value);
|
||||
}
|
||||
|
||||
public dynamic GetMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
return _ops.GetMember(obj, name, ignoreCase);
|
||||
}
|
||||
|
||||
public T GetMember<T>(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
return _ops.GetMember<T>(obj, name, ignoreCase);
|
||||
}
|
||||
|
||||
public bool TryGetMember(object obj, string name, bool ignoreCase, out object value)
|
||||
{
|
||||
return _ops.TryGetMember(obj, name, ignoreCase, out value);
|
||||
}
|
||||
|
||||
public bool ContainsMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
return _ops.ContainsMember(obj, name, ignoreCase);
|
||||
}
|
||||
|
||||
public void RemoveMember(object obj, string name, bool ignoreCase)
|
||||
{
|
||||
_ops.RemoveMember(obj, name, ignoreCase);
|
||||
}
|
||||
|
||||
public void SetMember(object obj, string name, object value, bool ignoreCase)
|
||||
{
|
||||
_ops.SetMember(obj, name, value, ignoreCase);
|
||||
}
|
||||
|
||||
public void SetMember<T>(object obj, string name, T value, bool ignoreCase)
|
||||
{
|
||||
_ops.SetMember(obj, name, value, ignoreCase);
|
||||
}
|
||||
|
||||
public T ConvertTo<T>(object obj)
|
||||
{
|
||||
return _ops.ConvertTo<T>(obj);
|
||||
}
|
||||
|
||||
public object ConvertTo(object obj, Type type)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
return _ops.ConvertTo(obj, type);
|
||||
}
|
||||
|
||||
public bool TryConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
return _ops.TryConvertTo<T>(obj, out result);
|
||||
}
|
||||
|
||||
public bool TryConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
return _ops.TryConvertTo(obj, type, out result);
|
||||
}
|
||||
|
||||
public T ExplicitConvertTo<T>(object obj)
|
||||
{
|
||||
return _ops.ExplicitConvertTo<T>(obj);
|
||||
}
|
||||
|
||||
public object ExplicitConvertTo(object obj, Type type)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
return _ops.ExplicitConvertTo(obj, type);
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
return _ops.TryExplicitConvertTo<T>(obj, out result);
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
return _ops.TryExplicitConvertTo(obj, type, out result);
|
||||
}
|
||||
|
||||
public T ImplicitConvertTo<T>(object obj)
|
||||
{
|
||||
return _ops.ImplicitConvertTo<T>(obj);
|
||||
}
|
||||
|
||||
public object ImplicitConvertTo(object obj, Type type)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
return _ops.ImplicitConvertTo(obj, type);
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo<T>(object obj, out T result)
|
||||
{
|
||||
return _ops.TryImplicitConvertTo<T>(obj, out result);
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo(object obj, Type type, out object result)
|
||||
{
|
||||
return _ops.TryImplicitConvertTo(obj, type, out result);
|
||||
}
|
||||
|
||||
public dynamic DoOperation(ExpressionType operation, object target)
|
||||
{
|
||||
return _ops.DoOperation<object, object>(operation, target);
|
||||
}
|
||||
|
||||
public TResult DoOperation<TTarget, TResult>(ExpressionType operation, TTarget target)
|
||||
{
|
||||
return _ops.DoOperation<TTarget, TResult>(operation, target);
|
||||
}
|
||||
|
||||
public dynamic DoOperation(ExpressionType operation, object target, object other)
|
||||
{
|
||||
return _ops.DoOperation<object, object, object>(operation, target, other);
|
||||
}
|
||||
|
||||
public TResult DoOperation<TTarget, TOther, TResult>(ExpressionType operation, TTarget target, TOther other)
|
||||
{
|
||||
return _ops.DoOperation<TTarget, TOther, TResult>(operation, target, other);
|
||||
}
|
||||
|
||||
public dynamic Add(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Add, self, other);
|
||||
}
|
||||
|
||||
public dynamic Subtract(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Subtract, self, other);
|
||||
}
|
||||
|
||||
public dynamic Power(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Power, self, other);
|
||||
}
|
||||
|
||||
public dynamic Multiply(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Multiply, self, other);
|
||||
}
|
||||
|
||||
public dynamic Divide(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Divide, self, other);
|
||||
}
|
||||
|
||||
public dynamic Modulo(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Modulo, self, other);
|
||||
}
|
||||
|
||||
public dynamic LeftShift(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.LeftShift, self, other);
|
||||
}
|
||||
|
||||
public dynamic RightShift(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.RightShift, self, other);
|
||||
}
|
||||
|
||||
public dynamic BitwiseAnd(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.And, self, other);
|
||||
}
|
||||
|
||||
public dynamic BitwiseOr(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.Or, self, other);
|
||||
}
|
||||
|
||||
public dynamic ExclusiveOr(object self, object other)
|
||||
{
|
||||
return DoOperation(ExpressionType.ExclusiveOr, self, other);
|
||||
}
|
||||
|
||||
public bool LessThan(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.LessThan, self, other));
|
||||
}
|
||||
|
||||
public bool GreaterThan(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.GreaterThan, self, other));
|
||||
}
|
||||
|
||||
public bool LessThanOrEqual(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.LessThanOrEqual, self, other));
|
||||
}
|
||||
|
||||
public bool GreaterThanOrEqual(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.GreaterThanOrEqual, self, other));
|
||||
}
|
||||
|
||||
public bool Equal(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.Equal, self, other));
|
||||
}
|
||||
|
||||
public bool NotEqual(object self, object other)
|
||||
{
|
||||
return ConvertTo<bool>(_ops.DoOperation<object, object, object>(ExpressionType.NotEqual, self, other));
|
||||
}
|
||||
|
||||
[Obsolete("Use Format method instead.")]
|
||||
public string GetCodeRepresentation(object obj)
|
||||
{
|
||||
return obj.ToString();
|
||||
}
|
||||
|
||||
public string Format(object obj)
|
||||
{
|
||||
return _ops.Format(obj);
|
||||
}
|
||||
|
||||
public IList<string> GetMemberNames(object obj)
|
||||
{
|
||||
return _ops.GetMemberNames(obj);
|
||||
}
|
||||
|
||||
public string GetDocumentation(object obj)
|
||||
{
|
||||
return _ops.GetDocumentation(obj);
|
||||
}
|
||||
|
||||
public IList<string> GetCallSignatures(object obj)
|
||||
{
|
||||
return _ops.GetCallSignatures(obj);
|
||||
}
|
||||
|
||||
[Obsolete("Use Invoke instead")]
|
||||
public object Call(object obj, params object[] parameters)
|
||||
{
|
||||
return _ops.Invoke(obj, parameters);
|
||||
}
|
||||
|
||||
[Obsolete("Use the ExpressionType overload instead")]
|
||||
public object DoOperation(Operators op, object target)
|
||||
{
|
||||
ExpressionType linqOp = GetLinqOp(op);
|
||||
return _ops.DoOperation<object, object>(linqOp, target);
|
||||
}
|
||||
|
||||
[Obsolete("Use ExpressionType overload instead")]
|
||||
public TResult DoOperation<TTarget, TResult>(Operators op, TTarget target)
|
||||
{
|
||||
return _ops.DoOperation<TTarget, TResult>(GetLinqOp(op), target);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private static ExpressionType GetLinqOp(Operators op)
|
||||
{
|
||||
ExpressionType? expressionType = null;
|
||||
return (op switch
|
||||
{
|
||||
Operators.Positive => ExpressionType.UnaryPlus,
|
||||
Operators.Negate => ExpressionType.Negate,
|
||||
Operators.OnesComplement => ExpressionType.OnesComplement,
|
||||
Operators.IsFalse => ExpressionType.IsFalse,
|
||||
Operators.Decrement => ExpressionType.Decrement,
|
||||
Operators.Increment => ExpressionType.Increment,
|
||||
_ => throw new InvalidOperationException($"Unrecognized shared operation: {op}"),
|
||||
});
|
||||
}
|
||||
|
||||
[Obsolete("Use Modulo instead")]
|
||||
public object Modulus(object self, object other)
|
||||
{
|
||||
return Modulo(self, other);
|
||||
}
|
||||
|
||||
[Obsolete("Use ExpressionType overload instead")]
|
||||
public object DoOperation(Operators op, object target, object other)
|
||||
{
|
||||
return _ops.DoOperation<object, object, object>(GetLinqBinaryOp(op), target, other);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
private static ExpressionType GetLinqBinaryOp(Operators op)
|
||||
{
|
||||
ExpressionType? expressionType = null;
|
||||
return (op switch
|
||||
{
|
||||
Operators.Add => ExpressionType.Add,
|
||||
Operators.BitwiseAnd => ExpressionType.And,
|
||||
Operators.Divide => ExpressionType.Divide,
|
||||
Operators.ExclusiveOr => ExpressionType.ExclusiveOr,
|
||||
Operators.Mod => ExpressionType.Modulo,
|
||||
Operators.Multiply => ExpressionType.Multiply,
|
||||
Operators.BitwiseOr => ExpressionType.Or,
|
||||
Operators.Power => ExpressionType.Power,
|
||||
Operators.RightShift => ExpressionType.RightShift,
|
||||
Operators.LeftShift => ExpressionType.LeftShift,
|
||||
Operators.Subtract => ExpressionType.Subtract,
|
||||
Operators.Equals => ExpressionType.Equal,
|
||||
Operators.GreaterThan => ExpressionType.GreaterThan,
|
||||
Operators.GreaterThanOrEqual => ExpressionType.GreaterThanOrEqual,
|
||||
Operators.LessThan => ExpressionType.LessThan,
|
||||
Operators.LessThanOrEqual => ExpressionType.LessThanOrEqual,
|
||||
Operators.NotEquals => ExpressionType.NotEqual,
|
||||
_ => throw new InvalidOperationException($"Unrecognized shared operation: {op}"),
|
||||
});
|
||||
}
|
||||
|
||||
[Obsolete("Use the ExpressionType overload instead")]
|
||||
public TResult DoOperation<TTarget, TOther, TResult>(Operators op, TTarget target, TOther other)
|
||||
{
|
||||
return _ops.DoOperation<TTarget, TOther, TResult>(GetLinqBinaryOp(op), target, other);
|
||||
}
|
||||
|
||||
[Obsolete("Use Invoke instead")]
|
||||
public ObjectHandle Call(ObjectHandle obj, params ObjectHandle[] parameters)
|
||||
{
|
||||
return Invoke(obj, parameters);
|
||||
}
|
||||
|
||||
[Obsolete("Use Invoke instead")]
|
||||
public ObjectHandle Call(ObjectHandle obj, params object[] parameters)
|
||||
{
|
||||
return Invoke(obj, parameters);
|
||||
}
|
||||
|
||||
[Obsolete("Use the ExpressionType overload instead")]
|
||||
public object DoOperation(Operators op, ObjectHandle target)
|
||||
{
|
||||
return DoOperation(op, GetLocalObject(target));
|
||||
}
|
||||
|
||||
[Obsolete("Use the ExpressionType enum instead")]
|
||||
public ObjectHandle DoOperation(Operators op, ObjectHandle target, ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle(DoOperation(op, GetLocalObject(target), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
[Obsolete("Use Modulo instead")]
|
||||
public ObjectHandle Modulus(ObjectHandle self, ObjectHandle other)
|
||||
{
|
||||
return Modulo(self, other);
|
||||
}
|
||||
|
||||
public bool IsCallable([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return IsCallable(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
public ObjectHandle Invoke([NotNull] ObjectHandle obj, params ObjectHandle[] parameters)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(parameters, "parameters");
|
||||
return new ObjectHandle((object)Invoke(GetLocalObject(obj), GetLocalObjects(parameters)));
|
||||
}
|
||||
|
||||
public ObjectHandle Invoke([NotNull] ObjectHandle obj, params object[] parameters)
|
||||
{
|
||||
return new ObjectHandle((object)Invoke(GetLocalObject(obj), parameters));
|
||||
}
|
||||
|
||||
public ObjectHandle Create([NotNull] ObjectHandle obj, [NotNull] params ObjectHandle[] parameters)
|
||||
{
|
||||
return new ObjectHandle((object)CreateInstance(GetLocalObject(obj), GetLocalObjects(parameters)));
|
||||
}
|
||||
|
||||
public ObjectHandle Create([NotNull] ObjectHandle obj, params object[] parameters)
|
||||
{
|
||||
return new ObjectHandle((object)CreateInstance(GetLocalObject(obj), parameters));
|
||||
}
|
||||
|
||||
public void SetMember([NotNull] ObjectHandle obj, string name, [NotNull] ObjectHandle value)
|
||||
{
|
||||
SetMember(GetLocalObject(obj), name, GetLocalObject(value));
|
||||
}
|
||||
|
||||
public void SetMember<T>([NotNull] ObjectHandle obj, string name, T value)
|
||||
{
|
||||
SetMember(GetLocalObject(obj), name, value);
|
||||
}
|
||||
|
||||
public ObjectHandle GetMember([NotNull] ObjectHandle obj, string name)
|
||||
{
|
||||
return new ObjectHandle((object)GetMember(GetLocalObject(obj), name));
|
||||
}
|
||||
|
||||
public T GetMember<T>([NotNull] ObjectHandle obj, string name)
|
||||
{
|
||||
return GetMember<T>(GetLocalObject(obj), name);
|
||||
}
|
||||
|
||||
public bool TryGetMember([NotNull] ObjectHandle obj, string name, out ObjectHandle value)
|
||||
{
|
||||
if (TryGetMember(GetLocalObject(obj), name, out var value2))
|
||||
{
|
||||
value = new ObjectHandle(value2);
|
||||
return true;
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ContainsMember([NotNull] ObjectHandle obj, string name)
|
||||
{
|
||||
return ContainsMember(GetLocalObject(obj), name);
|
||||
}
|
||||
|
||||
public void RemoveMember([NotNull] ObjectHandle obj, string name)
|
||||
{
|
||||
RemoveMember(GetLocalObject(obj), name);
|
||||
}
|
||||
|
||||
public ObjectHandle ConvertTo<T>([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return new ObjectHandle(ConvertTo<T>(GetLocalObject(obj)));
|
||||
}
|
||||
|
||||
public ObjectHandle ConvertTo([NotNull] ObjectHandle obj, Type type)
|
||||
{
|
||||
return new ObjectHandle(ConvertTo(GetLocalObject(obj), type));
|
||||
}
|
||||
|
||||
public bool TryConvertTo<T>([NotNull] ObjectHandle obj, out ObjectHandle result)
|
||||
{
|
||||
if (TryConvertTo<T>(GetLocalObject(obj), out var result2))
|
||||
{
|
||||
result = new ObjectHandle(result2);
|
||||
return true;
|
||||
}
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryConvertTo([NotNull] ObjectHandle obj, Type type, out ObjectHandle result)
|
||||
{
|
||||
if (TryConvertTo(GetLocalObject(obj), type, out var result2))
|
||||
{
|
||||
result = new ObjectHandle(result2);
|
||||
return true;
|
||||
}
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public ObjectHandle ExplicitConvertTo<T>([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return new ObjectHandle(_ops.ExplicitConvertTo<T>(GetLocalObject(obj)));
|
||||
}
|
||||
|
||||
public ObjectHandle ExplicitConvertTo([NotNull] ObjectHandle obj, Type type)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
return new ObjectHandle(_ops.ExplicitConvertTo(GetLocalObject(obj), type));
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo<T>([NotNull] ObjectHandle obj, out ObjectHandle result)
|
||||
{
|
||||
T result2;
|
||||
bool flag = _ops.TryExplicitConvertTo<T>(GetLocalObject(obj), out result2);
|
||||
if (flag)
|
||||
{
|
||||
result = new ObjectHandle(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public bool TryExplicitConvertTo([NotNull] ObjectHandle obj, Type type, out ObjectHandle result)
|
||||
{
|
||||
object result2;
|
||||
bool flag = _ops.TryExplicitConvertTo(GetLocalObject(obj), type, out result2);
|
||||
if (flag)
|
||||
{
|
||||
result = new ObjectHandle(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public ObjectHandle ImplicitConvertTo<T>([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return new ObjectHandle(_ops.ImplicitConvertTo<T>(GetLocalObject(obj)));
|
||||
}
|
||||
|
||||
public ObjectHandle ImplicitConvertTo([NotNull] ObjectHandle obj, Type type)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
return new ObjectHandle(_ops.ImplicitConvertTo(GetLocalObject(obj), type));
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo<T>([NotNull] ObjectHandle obj, out ObjectHandle result)
|
||||
{
|
||||
T result2;
|
||||
bool flag = _ops.TryImplicitConvertTo<T>(GetLocalObject(obj), out result2);
|
||||
if (flag)
|
||||
{
|
||||
result = new ObjectHandle(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public bool TryImplicitConvertTo([NotNull] ObjectHandle obj, Type type, out ObjectHandle result)
|
||||
{
|
||||
object result2;
|
||||
bool flag = _ops.TryImplicitConvertTo(GetLocalObject(obj), type, out result2);
|
||||
if (flag)
|
||||
{
|
||||
result = new ObjectHandle(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public T Unwrap<T>([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return ConvertTo<T>(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
public ObjectHandle DoOperation(ExpressionType op, [NotNull] ObjectHandle target)
|
||||
{
|
||||
return new ObjectHandle((object)DoOperation(op, GetLocalObject(target)));
|
||||
}
|
||||
|
||||
public ObjectHandle DoOperation(ExpressionType op, ObjectHandle target, ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)DoOperation(op, GetLocalObject(target), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Add([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Add(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Subtract([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Subtract(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Power([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Power(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Multiply([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Multiply(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Divide([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Divide(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle Modulo([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)Modulo(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle LeftShift([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)LeftShift(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle RightShift([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)RightShift(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle BitwiseAnd([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)BitwiseAnd(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle BitwiseOr([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)BitwiseOr(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public ObjectHandle ExclusiveOr([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return new ObjectHandle((object)ExclusiveOr(GetLocalObject(self), GetLocalObject(other)));
|
||||
}
|
||||
|
||||
public bool LessThan([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return LessThan(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public bool GreaterThan([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return GreaterThan(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public bool LessThanOrEqual([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return LessThanOrEqual(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public bool GreaterThanOrEqual([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return GreaterThanOrEqual(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public bool Equal([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return Equal(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public bool NotEqual([NotNull] ObjectHandle self, [NotNull] ObjectHandle other)
|
||||
{
|
||||
return NotEqual(GetLocalObject(self), GetLocalObject(other));
|
||||
}
|
||||
|
||||
public string Format([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return Format(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
public IList<string> GetMemberNames([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return GetMemberNames(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
public string GetDocumentation([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return GetDocumentation(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
public IList<string> GetCallSignatures([NotNull] ObjectHandle obj)
|
||||
{
|
||||
return GetCallSignatures(GetLocalObject(obj));
|
||||
}
|
||||
|
||||
private static object GetLocalObject([NotNull] ObjectHandle obj)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(obj, "obj");
|
||||
return obj.Unwrap();
|
||||
}
|
||||
|
||||
private static object[] GetLocalObjects(ObjectHandle[] ohs)
|
||||
{
|
||||
object[] array = new object[ohs.Length];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = GetLocalObject(ohs[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
44
AspClassic.Scripting/Hosting/OverloadDoc.cs
Normal file
44
AspClassic.Scripting/Hosting/OverloadDoc.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Serializable]
|
||||
public class OverloadDoc
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
private readonly string _doc;
|
||||
|
||||
private readonly ICollection<ParameterDoc> _params;
|
||||
|
||||
private readonly ParameterDoc _returnParam;
|
||||
|
||||
public string Name => _name;
|
||||
|
||||
public string Documentation => _doc;
|
||||
|
||||
public ICollection<ParameterDoc> Parameters => _params;
|
||||
|
||||
public ParameterDoc ReturnParameter => _returnParam;
|
||||
|
||||
public OverloadDoc(string name, string documentation, ICollection<ParameterDoc> parameters)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
ContractUtils.RequiresNotNullItems(parameters, "parameters");
|
||||
_name = name;
|
||||
_params = parameters;
|
||||
_doc = documentation;
|
||||
}
|
||||
|
||||
public OverloadDoc(string name, string documentation, ICollection<ParameterDoc> parameters, ParameterDoc returnParameter)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
ContractUtils.RequiresNotNullItems(parameters, "parameters");
|
||||
_name = name;
|
||||
_params = parameters;
|
||||
_doc = documentation;
|
||||
_returnParam = returnParameter;
|
||||
}
|
||||
}
|
53
AspClassic.Scripting/Hosting/ParameterDoc.cs
Normal file
53
AspClassic.Scripting/Hosting/ParameterDoc.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Serializable]
|
||||
public class ParameterDoc
|
||||
{
|
||||
private readonly string _name;
|
||||
|
||||
private readonly string _typeName;
|
||||
|
||||
private readonly string _doc;
|
||||
|
||||
private readonly ParameterFlags _flags;
|
||||
|
||||
public string Name => _name;
|
||||
|
||||
public string TypeName => _typeName;
|
||||
|
||||
public ParameterFlags Flags => _flags;
|
||||
|
||||
public string Documentation => _doc;
|
||||
|
||||
public ParameterDoc(string name)
|
||||
: this(name, null, null, ParameterFlags.None)
|
||||
{
|
||||
}
|
||||
|
||||
public ParameterDoc(string name, ParameterFlags paramFlags)
|
||||
: this(name, null, null, paramFlags)
|
||||
{
|
||||
}
|
||||
|
||||
public ParameterDoc(string name, string typeName)
|
||||
: this(name, typeName, null, ParameterFlags.None)
|
||||
{
|
||||
}
|
||||
|
||||
public ParameterDoc(string name, string typeName, string documentation)
|
||||
: this(name, typeName, documentation, ParameterFlags.None)
|
||||
{
|
||||
}
|
||||
|
||||
public ParameterDoc(string name, string typeName, string documentation, ParameterFlags paramFlags)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
_name = name;
|
||||
_flags = paramFlags;
|
||||
_typeName = typeName;
|
||||
_doc = documentation;
|
||||
}
|
||||
}
|
11
AspClassic.Scripting/Hosting/ParameterFlags.cs
Normal file
11
AspClassic.Scripting/Hosting/ParameterFlags.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Flags]
|
||||
public enum ParameterFlags
|
||||
{
|
||||
None = 0,
|
||||
ParamsArray = 1,
|
||||
ParamsDict = 2
|
||||
}
|
64
AspClassic.Scripting/Hosting/Providers/HostingHelpers.cs
Normal file
64
AspClassic.Scripting/Hosting/Providers/HostingHelpers.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Runtime.Remoting;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting.Providers;
|
||||
|
||||
public static class HostingHelpers
|
||||
{
|
||||
public static ScriptDomainManager GetDomainManager(ScriptRuntime runtime)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(runtime, "runtime");
|
||||
return runtime.Manager;
|
||||
}
|
||||
|
||||
public static LanguageContext GetLanguageContext(ScriptEngine engine)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(engine, "engine");
|
||||
return engine.LanguageContext;
|
||||
}
|
||||
|
||||
public static SourceUnit GetSourceUnit(ScriptSource scriptSource)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scriptSource, "scriptSource");
|
||||
return scriptSource.SourceUnit;
|
||||
}
|
||||
|
||||
public static ScriptCode GetScriptCode(CompiledCode compiledCode)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(compiledCode, "compiledCode");
|
||||
return compiledCode.ScriptCode;
|
||||
}
|
||||
|
||||
public static SharedIO GetSharedIO(ScriptIO io)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(io, "io");
|
||||
return io.SharedIO;
|
||||
}
|
||||
|
||||
public static Scope GetScope(ScriptScope scriptScope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scriptScope, "scriptScope");
|
||||
return scriptScope.Scope;
|
||||
}
|
||||
|
||||
public static ScriptScope CreateScriptScope(ScriptEngine engine, Scope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(engine, "engine");
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.Requires(!RemotingServices.IsTransparentProxy(engine), "engine", "The engine cannot be a transparent proxy");
|
||||
return new ScriptScope(engine, scope);
|
||||
}
|
||||
|
||||
[Obsolete("You should implement a service via LanguageContext and call ScriptEngine.GetService")]
|
||||
public static TRet CallEngine<T, TRet>(ScriptEngine engine, Func<LanguageContext, T, TRet> f, T arg)
|
||||
{
|
||||
return engine.Call(f, arg);
|
||||
}
|
||||
|
||||
public static DocumentationOperations CreateDocumentationOperations(DocumentationProvider provider)
|
||||
{
|
||||
return new DocumentationOperations(provider);
|
||||
}
|
||||
}
|
439
AspClassic.Scripting/Hosting/ScriptEngine.cs
Normal file
439
AspClassic.Scripting/Hosting/ScriptEngine.cs
Normal file
|
@ -0,0 +1,439 @@
|
|||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[DebuggerDisplay("{Setup.DisplayName}")]
|
||||
public sealed class ScriptEngine : MarshalByRefObject
|
||||
{
|
||||
private readonly LanguageContext _language;
|
||||
|
||||
private readonly ScriptRuntime _runtime;
|
||||
|
||||
private LanguageSetup _config;
|
||||
|
||||
private ObjectOperations _operations;
|
||||
|
||||
public ObjectOperations Operations
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_operations == null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _operations, CreateOperations(), null);
|
||||
}
|
||||
return _operations;
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageSetup Setup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
LanguageConfiguration languageConfig = _runtime.Manager.Configuration.GetLanguageConfig(_language);
|
||||
foreach (LanguageSetup languageSetup in _runtime.Setup.LanguageSetups)
|
||||
{
|
||||
if (languageConfig.ProviderName == new AssemblyQualifiedTypeName(languageSetup.TypeName))
|
||||
{
|
||||
return _config = languageSetup;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _config;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptRuntime Runtime => _runtime;
|
||||
|
||||
public Version LanguageVersion => _language.LanguageVersion;
|
||||
|
||||
internal LanguageContext LanguageContext => _language;
|
||||
|
||||
internal ScriptEngine(ScriptRuntime runtime, LanguageContext context)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_language = context;
|
||||
}
|
||||
|
||||
public ObjectOperations CreateOperations()
|
||||
{
|
||||
return new ObjectOperations(new DynamicOperations(_language), this);
|
||||
}
|
||||
|
||||
public ObjectOperations CreateOperations(ScriptScope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
return new ObjectOperations(_language.Operations, this);
|
||||
}
|
||||
|
||||
public dynamic Execute(string expression)
|
||||
{
|
||||
return CreateScriptSourceFromString(expression).Execute();
|
||||
}
|
||||
|
||||
public dynamic Execute(string expression, ScriptScope scope)
|
||||
{
|
||||
return CreateScriptSourceFromString(expression).Execute(scope);
|
||||
}
|
||||
|
||||
public T Execute<T>(string expression)
|
||||
{
|
||||
return Operations.ConvertTo<T>((object)Execute(expression));
|
||||
}
|
||||
|
||||
public T Execute<T>(string expression, ScriptScope scope)
|
||||
{
|
||||
return Operations.ConvertTo<T>((object)Execute(expression, scope));
|
||||
}
|
||||
|
||||
public ScriptScope ExecuteFile(string path)
|
||||
{
|
||||
return ExecuteFile(path, CreateScope());
|
||||
}
|
||||
|
||||
public ScriptScope ExecuteFile(string path, ScriptScope scope)
|
||||
{
|
||||
CreateScriptSourceFromFile(path).Execute(scope);
|
||||
return scope;
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(string expression, ScriptScope scope)
|
||||
{
|
||||
return new ObjectHandle((object)Execute(expression, scope));
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(string expression)
|
||||
{
|
||||
return new ObjectHandle((object)Execute(expression));
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(string expression, ScriptScope scope, out ObjectHandle exception)
|
||||
{
|
||||
exception = null;
|
||||
try
|
||||
{
|
||||
return new ObjectHandle((object)Execute(expression, scope));
|
||||
}
|
||||
catch (Exception o)
|
||||
{
|
||||
exception = new ObjectHandle(o);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(string expression, out ObjectHandle exception)
|
||||
{
|
||||
exception = null;
|
||||
try
|
||||
{
|
||||
return new ObjectHandle((object)Execute(expression));
|
||||
}
|
||||
catch (Exception o)
|
||||
{
|
||||
exception = new ObjectHandle(o);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope()
|
||||
{
|
||||
return new ScriptScope(this, new Scope());
|
||||
}
|
||||
|
||||
[Obsolete("IAttributesCollection is obsolete, use CreateScope(IDynamicMetaObjectProvider) instead")]
|
||||
public ScriptScope CreateScope(IAttributesCollection dictionary)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(dictionary, "dictionary");
|
||||
return new ScriptScope(this, new Scope(dictionary));
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope(IDynamicMetaObjectProvider storage)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(storage, "storage");
|
||||
return new ScriptScope(this, new Scope(storage));
|
||||
}
|
||||
|
||||
public ScriptScope GetScope(string path)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(path, "path");
|
||||
Scope scope = _language.GetScope(path);
|
||||
if (scope == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new ScriptScope(this, scope);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromString(string expression)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
return CreateScriptSource(new SourceStringContentProvider(expression), null, SourceCodeKind.AutoDetect);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromString(string code, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(code, "code");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
return CreateScriptSource(new SourceStringContentProvider(code), null, kind);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromString(string expression, string path)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
return CreateScriptSource(new SourceStringContentProvider(expression), path, SourceCodeKind.AutoDetect);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromString(string code, string path, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(code, "code");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
return CreateScriptSource(new SourceStringContentProvider(code), path, kind);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromFile(string path)
|
||||
{
|
||||
return CreateScriptSourceFromFile(path, StringUtils.DefaultEncoding, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromFile(string path, Encoding encoding)
|
||||
{
|
||||
return CreateScriptSourceFromFile(path, encoding, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSourceFromFile(string path, Encoding encoding, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(path, "path");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
if (!_language.CanCreateSourceCode)
|
||||
{
|
||||
throw new NotSupportedException("Invariant engine cannot create scripts");
|
||||
}
|
||||
return new ScriptSource(this, _language.CreateFileUnit(path, encoding, kind));
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(CodeObject content)
|
||||
{
|
||||
return CreateScriptSource(content, null, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(CodeObject content, string path)
|
||||
{
|
||||
return CreateScriptSource(content, path, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(CodeObject content, SourceCodeKind kind)
|
||||
{
|
||||
return CreateScriptSource(content, null, kind);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(CodeObject content, string path, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(content, "content");
|
||||
if (!_language.CanCreateSourceCode)
|
||||
{
|
||||
throw new NotSupportedException("Invariant engine cannot create scripts");
|
||||
}
|
||||
return new ScriptSource(this, _language.GenerateSourceCode(content, path, kind));
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(StreamContentProvider content, string path)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(content, "content");
|
||||
return CreateScriptSource(content, path, StringUtils.DefaultEncoding, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(StreamContentProvider content, string path, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(content, "content");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
return CreateScriptSource(content, path, encoding, SourceCodeKind.File);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(StreamContentProvider content, string path, Encoding encoding, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(content, "content");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
return CreateScriptSource(new LanguageBoundTextContentProvider(_language, content, encoding, path), path, kind);
|
||||
}
|
||||
|
||||
public ScriptSource CreateScriptSource(TextContentProvider contentProvider, string path, SourceCodeKind kind)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(contentProvider, "contentProvider");
|
||||
ContractUtils.Requires(kind.IsValid(), "kind");
|
||||
if (!_language.CanCreateSourceCode)
|
||||
{
|
||||
throw new NotSupportedException("Invariant engine cannot create scripts");
|
||||
}
|
||||
return new ScriptSource(this, _language.CreateSourceUnit(contentProvider, path, kind));
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.GetVariable instead")]
|
||||
public dynamic GetVariable(ScriptScope scope, string name)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
return scope.GetVariable(name);
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.RemoveVariable instead")]
|
||||
public bool RemoveVariable(ScriptScope scope, string name)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
return scope.RemoveVariable(name);
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.SetVariable instead")]
|
||||
public void SetVariable(ScriptScope scope, string name, object value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
scope.SetVariable(name, value);
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.TryGetVariable instead")]
|
||||
public bool TryGetVariable(ScriptScope scope, string name, out object value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
return scope.TryGetVariable(name, out value);
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.GetVariable<T> instead. If the target scope is not bound to any language or you need control over the conversion use ScriptScope.GetVariable and ScriptEngine.Operations.ConvertTo<T>")]
|
||||
public T GetVariable<T>(ScriptScope scope, string name)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
return Operations.ConvertTo<T>((object)GetVariable(scope, name));
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.GetVariable<T> instead. If the target scope is not bound to any language or you need control over the conversion use ScriptScope.GetVariable and ScriptEngine.Operations.ConvertTo<T>")]
|
||||
public bool TryGetVariable<T>(ScriptScope scope, string name, out T value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
if (TryGetVariable(scope, name, out var value2))
|
||||
{
|
||||
return Operations.TryConvertTo<T>(value2, out value);
|
||||
}
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.ContainsVariable instead")]
|
||||
public bool ContainsVariable(ScriptScope scope, string name)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
object value;
|
||||
return TryGetVariable(scope, name, out value);
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.GetVariableHandle instead")]
|
||||
public ObjectHandle GetVariableHandle(ScriptScope scope, string name)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
return new ObjectHandle((object)GetVariable(scope, name));
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.SetVariable instead")]
|
||||
public void SetVariable(ScriptScope scope, string name, ObjectHandle value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
SetVariable(scope, name, value.Unwrap());
|
||||
}
|
||||
|
||||
[Obsolete("Use ScriptScope.TryGetVariableHandle instead")]
|
||||
public bool TryGetVariableHandle(ScriptScope scope, string name, out ObjectHandle value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
if (TryGetVariable(scope, name, out var value2))
|
||||
{
|
||||
value = new ObjectHandle(value2);
|
||||
return true;
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TService GetService<TService>(params object[] args) where TService : class
|
||||
{
|
||||
if (typeof(TService) == typeof(TokenCategorizer))
|
||||
{
|
||||
TokenizerService service = _language.GetService<TokenizerService>(ArrayUtils.Insert(_language, args));
|
||||
if (service == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (TService)(object)new TokenCategorizer(service);
|
||||
}
|
||||
if (typeof(TService) == typeof(ExceptionOperations))
|
||||
{
|
||||
ExceptionOperations service2 = _language.GetService<ExceptionOperations>(new object[0]);
|
||||
if (service2 == null)
|
||||
{
|
||||
return (TService)(object)new ExceptionOperations(_language);
|
||||
}
|
||||
return (TService)(object)service2;
|
||||
}
|
||||
if (typeof(TService) == typeof(DocumentationOperations))
|
||||
{
|
||||
DocumentationProvider service3 = _language.GetService<DocumentationProvider>(args);
|
||||
if (service3 == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (TService)(object)new DocumentationOperations(service3);
|
||||
}
|
||||
return _language.GetService<TService>(args);
|
||||
}
|
||||
|
||||
public CompilerOptions GetCompilerOptions()
|
||||
{
|
||||
return _language.GetCompilerOptions();
|
||||
}
|
||||
|
||||
public CompilerOptions GetCompilerOptions(ScriptScope scope)
|
||||
{
|
||||
return _language.GetCompilerOptions(scope.Scope);
|
||||
}
|
||||
|
||||
public void SetSearchPaths(ICollection<string> paths)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(paths, "paths");
|
||||
ContractUtils.RequiresNotNullItems(paths, "paths");
|
||||
_language.SetSearchPaths(paths);
|
||||
}
|
||||
|
||||
public ICollection<string> GetSearchPaths()
|
||||
{
|
||||
return _language.GetSearchPaths();
|
||||
}
|
||||
|
||||
internal TRet Call<T, TRet>(Func<LanguageContext, T, TRet> f, T arg)
|
||||
{
|
||||
return f(_language, arg);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
43
AspClassic.Scripting/Hosting/ScriptHost.cs
Normal file
43
AspClassic.Scripting/Hosting/ScriptHost.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public class ScriptHost : MarshalByRefObject
|
||||
{
|
||||
private ScriptRuntime _runtime;
|
||||
|
||||
public ScriptRuntime Runtime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_runtime == null)
|
||||
{
|
||||
throw new InvalidOperationException("Host not initialized");
|
||||
}
|
||||
return _runtime;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual PlatformAdaptationLayer PlatformAdaptationLayer => PlatformAdaptationLayer.Default;
|
||||
|
||||
internal void SetRuntime(ScriptRuntime runtime)
|
||||
{
|
||||
_runtime = runtime;
|
||||
RuntimeAttached();
|
||||
}
|
||||
|
||||
protected virtual void RuntimeAttached()
|
||||
{
|
||||
}
|
||||
|
||||
protected internal virtual void EngineCreated(ScriptEngine engine)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
15
AspClassic.Scripting/Hosting/ScriptHostProxy.cs
Normal file
15
AspClassic.Scripting/Hosting/ScriptHostProxy.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using AspClassic.Scripting.Runtime;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
internal sealed class ScriptHostProxy : DynamicRuntimeHostingProvider
|
||||
{
|
||||
private readonly ScriptHost _host;
|
||||
|
||||
public override PlatformAdaptationLayer PlatformAdaptationLayer => _host.PlatformAdaptationLayer;
|
||||
|
||||
public ScriptHostProxy(ScriptHost host)
|
||||
{
|
||||
_host = host;
|
||||
}
|
||||
}
|
92
AspClassic.Scripting/Hosting/ScriptIO.cs
Normal file
92
AspClassic.Scripting/Hosting/ScriptIO.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class ScriptIO : MarshalByRefObject
|
||||
{
|
||||
private readonly SharedIO _io;
|
||||
|
||||
public Stream InputStream => _io.InputStream;
|
||||
|
||||
public Stream OutputStream => _io.OutputStream;
|
||||
|
||||
public Stream ErrorStream => _io.ErrorStream;
|
||||
|
||||
public TextReader InputReader => _io.InputReader;
|
||||
|
||||
public TextWriter OutputWriter => _io.OutputWriter;
|
||||
|
||||
public TextWriter ErrorWriter => _io.ErrorWriter;
|
||||
|
||||
public Encoding InputEncoding => _io.InputEncoding;
|
||||
|
||||
public Encoding OutputEncoding => _io.OutputEncoding;
|
||||
|
||||
public Encoding ErrorEncoding => _io.ErrorEncoding;
|
||||
|
||||
internal SharedIO SharedIO => _io;
|
||||
|
||||
internal ScriptIO(SharedIO io)
|
||||
{
|
||||
_io = io;
|
||||
}
|
||||
|
||||
public void SetOutput(Stream stream, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
_io.SetOutput(stream, new StreamWriter(stream, encoding));
|
||||
}
|
||||
|
||||
public void SetOutput(Stream stream, TextWriter writer)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(writer, "writer");
|
||||
_io.SetOutput(stream, writer);
|
||||
}
|
||||
|
||||
public void SetErrorOutput(Stream stream, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
_io.SetErrorOutput(stream, new StreamWriter(stream, encoding));
|
||||
}
|
||||
|
||||
public void SetErrorOutput(Stream stream, TextWriter writer)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(writer, "writer");
|
||||
_io.SetErrorOutput(stream, writer);
|
||||
}
|
||||
|
||||
public void SetInput(Stream stream, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
_io.SetInput(stream, new StreamReader(stream, encoding), encoding);
|
||||
}
|
||||
|
||||
public void SetInput(Stream stream, TextReader reader, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(stream, "stream");
|
||||
ContractUtils.RequiresNotNull(reader, "writer");
|
||||
ContractUtils.RequiresNotNull(encoding, "encoding");
|
||||
_io.SetInput(stream, reader, encoding);
|
||||
}
|
||||
|
||||
public void RedirectToConsole()
|
||||
{
|
||||
_io.RedirectToConsole();
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
309
AspClassic.Scripting/Hosting/ScriptRuntime.cs
Normal file
309
AspClassic.Scripting/Hosting/ScriptRuntime.cs
Normal file
|
@ -0,0 +1,309 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class ScriptRuntime : MarshalByRefObject
|
||||
{
|
||||
private readonly Dictionary<LanguageContext, ScriptEngine> _engines;
|
||||
|
||||
private readonly ScriptDomainManager _manager;
|
||||
|
||||
private readonly InvariantContext _invariantContext;
|
||||
|
||||
private readonly ScriptIO _io;
|
||||
|
||||
private readonly ScriptHost _host;
|
||||
|
||||
private readonly ScriptRuntimeSetup _setup;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
private ScriptScope _globals;
|
||||
|
||||
private Scope _scopeGlobals;
|
||||
|
||||
private ScriptEngine _invariantEngine;
|
||||
|
||||
internal ScriptDomainManager Manager => _manager;
|
||||
|
||||
public ScriptHost Host => _host;
|
||||
|
||||
public ScriptIO IO => _io;
|
||||
|
||||
public ScriptRuntimeSetup Setup => _setup;
|
||||
|
||||
public ScriptScope Globals
|
||||
{
|
||||
get
|
||||
{
|
||||
Scope globals = _manager.Globals;
|
||||
if (_scopeGlobals == globals)
|
||||
{
|
||||
return _globals;
|
||||
}
|
||||
lock (_lock)
|
||||
{
|
||||
if (_scopeGlobals != globals)
|
||||
{
|
||||
_globals = new ScriptScope(InvariantEngine, globals);
|
||||
_scopeGlobals = globals;
|
||||
}
|
||||
return _globals;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
ContractUtils.RequiresNotNull(value, "value");
|
||||
lock (_lock)
|
||||
{
|
||||
_globals = value;
|
||||
_manager.Globals = value.Scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectOperations Operations => InvariantEngine.Operations;
|
||||
|
||||
internal ScriptEngine InvariantEngine
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_invariantEngine == null)
|
||||
{
|
||||
_invariantEngine = GetEngine(_invariantContext);
|
||||
}
|
||||
return _invariantEngine;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptRuntime(ScriptRuntimeSetup setup)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(setup, "setup");
|
||||
DlrConfiguration configuration = setup.ToConfiguration();
|
||||
_setup = setup;
|
||||
try
|
||||
{
|
||||
_host = (ScriptHost)Activator.CreateInstance(setup.HostType, Utils.CollectionExtensions.ToArray(setup.HostArguments));
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
throw new InvalidImplementationException(Strings.InvalidCtorImplementation(setup.HostType, ex.InnerException.Message), ex.InnerException);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
throw new InvalidImplementationException(Strings.InvalidCtorImplementation(setup.HostType, ex2.Message), ex2);
|
||||
}
|
||||
ScriptHostProxy hostingProvider = new ScriptHostProxy(_host);
|
||||
_manager = new ScriptDomainManager(hostingProvider, configuration);
|
||||
_invariantContext = new InvariantContext(_manager);
|
||||
_io = new ScriptIO(_manager.SharedIO);
|
||||
_engines = new Dictionary<LanguageContext, ScriptEngine>();
|
||||
_globals = new ScriptScope(GetEngineNoLockNoNotification(_invariantContext, out var _), _manager.Globals);
|
||||
_host.SetRuntime(this);
|
||||
if (!setup.Options.TryGetValue("NoDefaultReferences", out var value) || !Convert.ToBoolean(value))
|
||||
{
|
||||
LoadAssembly(typeof(string).Assembly);
|
||||
LoadAssembly(typeof(Debug).Assembly);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScriptRuntime CreateFromConfiguration()
|
||||
{
|
||||
return new ScriptRuntime(ScriptRuntimeSetup.ReadConfiguration());
|
||||
}
|
||||
|
||||
public static ScriptRuntime CreateRemote(AppDomain domain, ScriptRuntimeSetup setup)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(domain, "domain");
|
||||
return (ScriptRuntime)domain.CreateInstanceAndUnwrap(typeof(ScriptRuntime).Assembly.FullName, typeof(ScriptRuntime).FullName, ignoreCase: false, BindingFlags.Default, null, new object[1] { setup }, null, null);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ScriptEngine GetEngine(string languageName)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(languageName, "languageName");
|
||||
if (!TryGetEngine(languageName, out var engine))
|
||||
{
|
||||
throw new ArgumentException($"Unknown language name: '{languageName}'");
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
public ScriptEngine GetEngineByTypeName(string assemblyQualifiedTypeName)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(assemblyQualifiedTypeName, "assemblyQualifiedTypeName");
|
||||
return GetEngine(_manager.GetLanguageByTypeName(assemblyQualifiedTypeName));
|
||||
}
|
||||
|
||||
public ScriptEngine GetEngineByFileExtension(string fileExtension)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(fileExtension, "fileExtension");
|
||||
if (!TryGetEngineByFileExtension(fileExtension, out var engine))
|
||||
{
|
||||
throw new ArgumentException($"Unknown file extension: '{fileExtension}'");
|
||||
}
|
||||
return engine;
|
||||
}
|
||||
|
||||
public bool TryGetEngine(string languageName, out ScriptEngine engine)
|
||||
{
|
||||
if (!_manager.TryGetLanguage(languageName, out var language))
|
||||
{
|
||||
engine = null;
|
||||
return false;
|
||||
}
|
||||
engine = GetEngine(language);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetEngineByFileExtension(string fileExtension, out ScriptEngine engine)
|
||||
{
|
||||
if (!_manager.TryGetLanguageByFileExtension(fileExtension, out var language))
|
||||
{
|
||||
engine = null;
|
||||
return false;
|
||||
}
|
||||
engine = GetEngine(language);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal ScriptEngine GetEngine(LanguageContext language)
|
||||
{
|
||||
ScriptEngine engineNoLockNoNotification;
|
||||
bool freshEngineCreated;
|
||||
lock (_engines)
|
||||
{
|
||||
engineNoLockNoNotification = GetEngineNoLockNoNotification(language, out freshEngineCreated);
|
||||
}
|
||||
if (freshEngineCreated && !object.ReferenceEquals(language, _invariantContext))
|
||||
{
|
||||
_host.EngineCreated(engineNoLockNoNotification);
|
||||
}
|
||||
return engineNoLockNoNotification;
|
||||
}
|
||||
|
||||
private ScriptEngine GetEngineNoLockNoNotification(LanguageContext language, out bool freshEngineCreated)
|
||||
{
|
||||
if (freshEngineCreated = !_engines.TryGetValue(language, out var value))
|
||||
{
|
||||
value = new ScriptEngine(this, language);
|
||||
Thread.MemoryBarrier();
|
||||
_engines.Add(language, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope()
|
||||
{
|
||||
return InvariantEngine.CreateScope();
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope(string languageId)
|
||||
{
|
||||
return GetEngine(languageId).CreateScope();
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope(IDynamicMetaObjectProvider storage)
|
||||
{
|
||||
return InvariantEngine.CreateScope(storage);
|
||||
}
|
||||
|
||||
public ScriptScope CreateScope(string languageId, IDynamicMetaObjectProvider storage)
|
||||
{
|
||||
return GetEngine(languageId).CreateScope(storage);
|
||||
}
|
||||
|
||||
[Obsolete("IAttributesCollection is obsolete, use CreateScope(IDynamicMetaObjectProvider) instead")]
|
||||
public ScriptScope CreateScope(IAttributesCollection dictionary)
|
||||
{
|
||||
return InvariantEngine.CreateScope(dictionary);
|
||||
}
|
||||
|
||||
[Obsolete("IAttributesCollection is obsolete, use CreateScope(string, IDynamicMetaObjectProvider) instead")]
|
||||
public ScriptScope CreateScope(string languageId, IAttributesCollection storage)
|
||||
{
|
||||
return GetEngine(languageId).CreateScope(storage);
|
||||
}
|
||||
|
||||
public ScriptScope ExecuteFile(string path)
|
||||
{
|
||||
ContractUtils.RequiresNotEmpty(path, "path");
|
||||
string extension = Path.GetExtension(path);
|
||||
if (!TryGetEngineByFileExtension(extension, out var engine))
|
||||
{
|
||||
throw new ArgumentException($"File extension '{extension}' is not associated with any language.");
|
||||
}
|
||||
return engine.ExecuteFile(path);
|
||||
}
|
||||
|
||||
public ScriptScope UseFile(string path)
|
||||
{
|
||||
ContractUtils.RequiresNotEmpty(path, "path");
|
||||
string extension = Path.GetExtension(path);
|
||||
if (!TryGetEngineByFileExtension(extension, out var engine))
|
||||
{
|
||||
throw new ArgumentException($"File extension '{extension}' is not associated with any language.");
|
||||
}
|
||||
ICollection<string> searchPaths = engine.GetSearchPaths();
|
||||
if (searchPaths.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"No search paths defined for language '{engine.Setup.DisplayName}'");
|
||||
}
|
||||
foreach (string item in searchPaths)
|
||||
{
|
||||
string path2 = Path.Combine(item, path);
|
||||
ScriptScope scope = engine.GetScope(path2);
|
||||
if (scope != null)
|
||||
{
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
foreach (string item2 in searchPaths)
|
||||
{
|
||||
string path3 = Path.Combine(item2, path);
|
||||
if (_manager.Platform.FileExists(path3))
|
||||
{
|
||||
return ExecuteFile(path3);
|
||||
}
|
||||
}
|
||||
string arg = Utils.CollectionExtensions.Aggregate(searchPaths ,(string x, string y) => x + ", " + y);
|
||||
throw new FileNotFoundException($"File '{path}' not found in language's search path: {arg}");
|
||||
}
|
||||
|
||||
public void LoadAssembly(Assembly assembly)
|
||||
{
|
||||
_manager.LoadAssembly(assembly);
|
||||
}
|
||||
|
||||
public ObjectOperations CreateOperations()
|
||||
{
|
||||
return InvariantEngine.CreateOperations();
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
List<LanguageContext> list;
|
||||
lock (_engines)
|
||||
{
|
||||
list = new List<LanguageContext>(_engines.Keys);
|
||||
}
|
||||
foreach (LanguageContext item in list)
|
||||
{
|
||||
item.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
151
AspClassic.Scripting/Hosting/ScriptRuntimeSetup.cs
Normal file
151
AspClassic.Scripting/Hosting/ScriptRuntimeSetup.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using AspClassic.Scripting.Hosting.Configuration;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[Serializable]
|
||||
public sealed class ScriptRuntimeSetup
|
||||
{
|
||||
private Type _hostType;
|
||||
|
||||
private IList<object> _hostArguments;
|
||||
|
||||
private IList<LanguageSetup> _languageSetups;
|
||||
|
||||
private bool _debugMode;
|
||||
|
||||
private bool _privateBinding;
|
||||
|
||||
private IDictionary<string, object> _options;
|
||||
|
||||
private bool _frozen;
|
||||
|
||||
public IList<LanguageSetup> LanguageSetups => _languageSetups;
|
||||
|
||||
public bool DebugMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _debugMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
_debugMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool PrivateBinding
|
||||
{
|
||||
get
|
||||
{
|
||||
return _privateBinding;
|
||||
}
|
||||
set
|
||||
{
|
||||
CheckFrozen();
|
||||
_privateBinding = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Type HostType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hostType;
|
||||
}
|
||||
set
|
||||
{
|
||||
ContractUtils.RequiresNotNull(value, "value");
|
||||
ContractUtils.Requires(typeof(ScriptHost).IsAssignableFrom(value), "value", "Must be ScriptHost or a derived type of ScriptHost");
|
||||
CheckFrozen();
|
||||
_hostType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Options => _options;
|
||||
|
||||
public IList<object> HostArguments
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hostArguments;
|
||||
}
|
||||
set
|
||||
{
|
||||
ContractUtils.RequiresNotNull(value, "value");
|
||||
CheckFrozen();
|
||||
_hostArguments = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptRuntimeSetup()
|
||||
{
|
||||
_languageSetups = new List<LanguageSetup>();
|
||||
_options = new Dictionary<string, object>();
|
||||
_hostType = typeof(ScriptHost);
|
||||
_hostArguments = ArrayUtils.EmptyObjects;
|
||||
}
|
||||
|
||||
internal DlrConfiguration ToConfiguration()
|
||||
{
|
||||
ContractUtils.Requires(_languageSetups.Count > 0, "ScriptRuntimeSetup must have at least one LanguageSetup");
|
||||
ReadOnlyCollection<LanguageSetup> readOnlyCollection = new ReadOnlyCollection<LanguageSetup>(ArrayUtils.MakeArray(_languageSetups));
|
||||
ReadOnlyCollection<object> hostArguments = new ReadOnlyCollection<object>(ArrayUtils.MakeArray(_hostArguments));
|
||||
AspClassic.Scripting.Utils.ReadOnlyDictionary<string, object> options = new AspClassic.Scripting.Utils.ReadOnlyDictionary<string, object>(new Dictionary<string, object>(_options));
|
||||
DlrConfiguration dlrConfiguration = new DlrConfiguration(_debugMode, _privateBinding, options);
|
||||
foreach (LanguageSetup item in readOnlyCollection)
|
||||
{
|
||||
dlrConfiguration.AddLanguage(item.TypeName, item.DisplayName, item.Names, item.FileExtensions, item.Options);
|
||||
}
|
||||
_languageSetups = readOnlyCollection;
|
||||
_options = options;
|
||||
_hostArguments = hostArguments;
|
||||
Freeze(readOnlyCollection);
|
||||
return dlrConfiguration;
|
||||
}
|
||||
|
||||
private void Freeze(ReadOnlyCollection<LanguageSetup> setups)
|
||||
{
|
||||
foreach (LanguageSetup setup in setups)
|
||||
{
|
||||
setup.Freeze();
|
||||
}
|
||||
_frozen = true;
|
||||
}
|
||||
|
||||
private void CheckFrozen()
|
||||
{
|
||||
if (_frozen)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot modify ScriptRuntimeSetup after it has been used to create a ScriptRuntime");
|
||||
}
|
||||
}
|
||||
|
||||
public static ScriptRuntimeSetup ReadConfiguration()
|
||||
{
|
||||
ScriptRuntimeSetup scriptRuntimeSetup = new ScriptRuntimeSetup();
|
||||
Section.LoadRuntimeSetup(scriptRuntimeSetup, null);
|
||||
return scriptRuntimeSetup;
|
||||
}
|
||||
|
||||
public static ScriptRuntimeSetup ReadConfiguration(Stream configFileStream)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(configFileStream, "configFileStream");
|
||||
ScriptRuntimeSetup scriptRuntimeSetup = new ScriptRuntimeSetup();
|
||||
Section.LoadRuntimeSetup(scriptRuntimeSetup, configFileStream);
|
||||
return scriptRuntimeSetup;
|
||||
}
|
||||
|
||||
public static ScriptRuntimeSetup ReadConfiguration(string configFilePath)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(configFilePath, "configFilePath");
|
||||
using FileStream configFileStream = File.OpenRead(configFilePath);
|
||||
return ReadConfiguration(configFileStream);
|
||||
}
|
||||
}
|
203
AspClassic.Scripting/Hosting/ScriptScope.cs
Normal file
203
AspClassic.Scripting/Hosting/ScriptScope.cs
Normal file
|
@ -0,0 +1,203 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[DebuggerTypeProxy(typeof(DebugView))]
|
||||
public sealed class ScriptScope : MarshalByRefObject, IDynamicMetaObjectProvider
|
||||
{
|
||||
internal sealed class DebugView
|
||||
{
|
||||
private readonly ScriptScope _scope;
|
||||
|
||||
public ScriptEngine Language => _scope._engine;
|
||||
|
||||
public Hashtable Variables
|
||||
{
|
||||
get
|
||||
{
|
||||
Hashtable hashtable = new Hashtable();
|
||||
foreach (KeyValuePair<string, object> item in _scope.GetItems())
|
||||
{
|
||||
hashtable[item.Key] = item.Value;
|
||||
}
|
||||
return hashtable;
|
||||
}
|
||||
}
|
||||
|
||||
public DebugView(ScriptScope scope)
|
||||
{
|
||||
_scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class Meta : DynamicMetaObject
|
||||
{
|
||||
internal Meta(Expression parameter, ScriptScope scope)
|
||||
: base(parameter, BindingRestrictions.Empty, scope)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindGetMember(GetMemberBinder action)
|
||||
{
|
||||
ParameterExpression parameterExpression = Expression.Variable(typeof(object), "result");
|
||||
DynamicMetaObject dynamicMetaObject = action.FallbackGetMember(this);
|
||||
return new DynamicMetaObject(Expression.Block(new ParameterExpression[1] { parameterExpression }, Expression.Condition(Expression.Call(Expression.Convert(base.Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("TryGetVariable", new Type[2]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(object).MakeByRefType()
|
||||
}), Expression.Constant(action.Name), parameterExpression), parameterExpression, Expression.Convert(dynamicMetaObject.Expression, typeof(object)))), BindingRestrictions.GetTypeRestriction(base.Expression, typeof(ScriptScope)).Merge(dynamicMetaObject.Restrictions));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindSetMember(SetMemberBinder action, DynamicMetaObject value)
|
||||
{
|
||||
Expression arg = Expression.Convert(value.Expression, typeof(object));
|
||||
return new DynamicMetaObject(Expression.Block(Expression.Call(Expression.Convert(base.Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("SetVariable", new Type[2]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(object)
|
||||
}), Expression.Constant(action.Name), arg), arg), base.Restrictions.Merge(value.Restrictions).Merge(BindingRestrictions.GetTypeRestriction(base.Expression, typeof(ScriptScope))));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder action)
|
||||
{
|
||||
DynamicMetaObject dynamicMetaObject = action.FallbackDeleteMember(this);
|
||||
return new DynamicMetaObject(Expression.IfThenElse(Expression.Call(Expression.Convert(base.Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("RemoveVariable"), Expression.Constant(action.Name)), Expression.Empty(), dynamicMetaObject.Expression), base.Restrictions.Merge(BindingRestrictions.GetTypeRestriction(base.Expression, typeof(ScriptScope))).Merge(dynamicMetaObject.Restrictions));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder action, DynamicMetaObject[] args)
|
||||
{
|
||||
DynamicMetaObject dynamicMetaObject = action.FallbackInvokeMember(this, args);
|
||||
ParameterExpression parameterExpression = Expression.Variable(typeof(object), "result");
|
||||
DynamicMetaObject dynamicMetaObject2 = action.FallbackInvoke(new DynamicMetaObject(parameterExpression, BindingRestrictions.Empty), args, null);
|
||||
return new DynamicMetaObject(Expression.Block(new ParameterExpression[1] { parameterExpression }, Expression.Condition(Expression.Call(Expression.Convert(base.Expression, typeof(ScriptScope)), typeof(ScriptScope).GetMethod("TryGetVariable", new Type[2]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(object).MakeByRefType()
|
||||
}), Expression.Constant(action.Name), parameterExpression), Expression.Convert(dynamicMetaObject2.Expression, typeof(object)), Expression.Convert(dynamicMetaObject.Expression, typeof(object)))), BindingRestrictions.Combine(args).Merge(BindingRestrictions.GetTypeRestriction(base.Expression, typeof(ScriptScope))).Merge(dynamicMetaObject.Restrictions));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return ((ScriptScope)base.Value).GetVariableNames();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Scope _scope;
|
||||
|
||||
private readonly ScriptEngine _engine;
|
||||
|
||||
internal Scope Scope => _scope;
|
||||
|
||||
public ScriptEngine Engine => _engine;
|
||||
|
||||
public ScriptScope(ScriptEngine engine, Scope scope)
|
||||
{
|
||||
_scope = scope;
|
||||
_engine = engine;
|
||||
}
|
||||
|
||||
public dynamic GetVariable(string name)
|
||||
{
|
||||
return _engine.LanguageContext.ScopeGetVariable(Scope, name);
|
||||
}
|
||||
|
||||
public T GetVariable<T>(string name)
|
||||
{
|
||||
return _engine.LanguageContext.ScopeGetVariable<T>(Scope, name);
|
||||
}
|
||||
|
||||
public bool TryGetVariable(string name, out dynamic value)
|
||||
{
|
||||
return _engine.LanguageContext.ScopeTryGetVariable(Scope, name, out value);
|
||||
}
|
||||
|
||||
public bool TryGetVariable<T>(string name, out T value)
|
||||
{
|
||||
if (_engine.LanguageContext.ScopeTryGetVariable(Scope, name, out var value2))
|
||||
{
|
||||
value = _engine.Operations.ConvertTo<T>(value2);
|
||||
return true;
|
||||
}
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetVariable(string name, object value)
|
||||
{
|
||||
_engine.LanguageContext.ScopeSetVariable(Scope, name, value);
|
||||
}
|
||||
|
||||
public ObjectHandle GetVariableHandle(string name)
|
||||
{
|
||||
return new ObjectHandle((object)GetVariable(name));
|
||||
}
|
||||
|
||||
public bool TryGetVariableHandle(string name, out ObjectHandle handle)
|
||||
{
|
||||
if (TryGetVariable(name, out var value))
|
||||
{
|
||||
handle = new ObjectHandle(value);
|
||||
return true;
|
||||
}
|
||||
handle = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetVariable(string name, ObjectHandle handle)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(handle, "handle");
|
||||
SetVariable(name, handle.Unwrap());
|
||||
}
|
||||
|
||||
public bool ContainsVariable(string name)
|
||||
{
|
||||
object value;
|
||||
return TryGetVariable(name, out value);
|
||||
}
|
||||
|
||||
public bool RemoveVariable(string name)
|
||||
{
|
||||
if (_engine.Operations.ContainsMember(_scope, name))
|
||||
{
|
||||
_engine.Operations.RemoveMember(_scope, name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetVariableNames()
|
||||
{
|
||||
return _engine.Operations.GetMemberNames((object)_scope.Storage);
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<string, object>> GetItems()
|
||||
{
|
||||
List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
|
||||
foreach (string variableName in GetVariableNames())
|
||||
{
|
||||
list.Add(new KeyValuePair<string, object>(variableName, (object)_engine.Operations.GetMember((object)_scope.Storage, variableName)));
|
||||
}
|
||||
list.TrimExcess();
|
||||
return list;
|
||||
}
|
||||
|
||||
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new Meta(parameter, this);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
163
AspClassic.Scripting/Hosting/ScriptSource.cs
Normal file
163
AspClassic.Scripting/Hosting/ScriptSource.cs
Normal file
|
@ -0,0 +1,163 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
[DebuggerDisplay("{Path ?? \"<anonymous>\"}")]
|
||||
public sealed class ScriptSource : MarshalByRefObject
|
||||
{
|
||||
private readonly ScriptEngine _engine;
|
||||
|
||||
private readonly SourceUnit _unit;
|
||||
|
||||
internal SourceUnit SourceUnit => _unit;
|
||||
|
||||
public string Path => _unit.Path;
|
||||
|
||||
public SourceCodeKind Kind => _unit.Kind;
|
||||
|
||||
public ScriptEngine Engine => _engine;
|
||||
|
||||
internal ScriptSource(ScriptEngine engine, SourceUnit sourceUnit)
|
||||
{
|
||||
_unit = sourceUnit;
|
||||
_engine = engine;
|
||||
}
|
||||
|
||||
public CompiledCode Compile()
|
||||
{
|
||||
return CompileInternal(null, null);
|
||||
}
|
||||
|
||||
public CompiledCode Compile(ErrorListener errorListener)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(errorListener, "errorListener");
|
||||
return CompileInternal(null, errorListener);
|
||||
}
|
||||
|
||||
public CompiledCode Compile(CompilerOptions compilerOptions)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(compilerOptions, "compilerOptions");
|
||||
return CompileInternal(compilerOptions, null);
|
||||
}
|
||||
|
||||
public CompiledCode Compile(CompilerOptions compilerOptions, ErrorListener errorListener)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(errorListener, "errorListener");
|
||||
ContractUtils.RequiresNotNull(compilerOptions, "compilerOptions");
|
||||
return CompileInternal(compilerOptions, errorListener);
|
||||
}
|
||||
|
||||
private CompiledCode CompileInternal(CompilerOptions compilerOptions, ErrorListener errorListener)
|
||||
{
|
||||
ErrorSink errorSink = new ErrorListenerProxySink(this, errorListener);
|
||||
ScriptCode scriptCode = ((compilerOptions != null) ? _unit.Compile(compilerOptions, errorSink) : _unit.Compile(errorSink));
|
||||
if (scriptCode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new CompiledCode(_engine, scriptCode);
|
||||
}
|
||||
|
||||
public dynamic Execute(ScriptScope scope)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
return _unit.Execute(scope.Scope);
|
||||
}
|
||||
|
||||
public dynamic Execute()
|
||||
{
|
||||
return _unit.Execute();
|
||||
}
|
||||
|
||||
public T Execute<T>(ScriptScope scope)
|
||||
{
|
||||
return _engine.Operations.ConvertTo<T>((object)Execute(scope));
|
||||
}
|
||||
|
||||
public T Execute<T>()
|
||||
{
|
||||
return _engine.Operations.ConvertTo<T>((object)Execute());
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap(ScriptScope scope)
|
||||
{
|
||||
return new ObjectHandle((object)Execute(scope));
|
||||
}
|
||||
|
||||
public ObjectHandle ExecuteAndWrap()
|
||||
{
|
||||
return new ObjectHandle((object)Execute());
|
||||
}
|
||||
|
||||
public int ExecuteProgram()
|
||||
{
|
||||
return _unit.LanguageContext.ExecuteProgram(_unit);
|
||||
}
|
||||
|
||||
public ScriptCodeParseResult GetCodeProperties()
|
||||
{
|
||||
return _unit.GetCodeProperties();
|
||||
}
|
||||
|
||||
public ScriptCodeParseResult GetCodeProperties(CompilerOptions options)
|
||||
{
|
||||
return _unit.GetCodeProperties(options);
|
||||
}
|
||||
|
||||
public SourceCodeReader GetReader()
|
||||
{
|
||||
return _unit.GetReader();
|
||||
}
|
||||
|
||||
public Encoding DetectEncoding()
|
||||
{
|
||||
using SourceCodeReader sourceCodeReader = _unit.GetReader();
|
||||
return sourceCodeReader.Encoding;
|
||||
}
|
||||
|
||||
public string[] GetCodeLines(int start, int count)
|
||||
{
|
||||
return _unit.GetCodeLines(start, count);
|
||||
}
|
||||
|
||||
public string GetCodeLine(int line)
|
||||
{
|
||||
return _unit.GetCodeLine(line);
|
||||
}
|
||||
|
||||
public string GetCode()
|
||||
{
|
||||
return _unit.GetCode();
|
||||
}
|
||||
|
||||
public int MapLine(int line)
|
||||
{
|
||||
return _unit.MapLine(line);
|
||||
}
|
||||
|
||||
public SourceSpan MapLine(SourceSpan span)
|
||||
{
|
||||
return new SourceSpan(_unit.MakeLocation(span.Start), _unit.MakeLocation(span.End));
|
||||
}
|
||||
|
||||
public SourceLocation MapLine(SourceLocation location)
|
||||
{
|
||||
return _unit.MakeLocation(location);
|
||||
}
|
||||
|
||||
public string MapLinetoFile(int line)
|
||||
{
|
||||
return _unit.Path;
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
65
AspClassic.Scripting/Hosting/TokenCategorizer.cs
Normal file
65
AspClassic.Scripting/Hosting/TokenCategorizer.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
|
||||
namespace AspClassic.Scripting.Hosting;
|
||||
|
||||
public sealed class TokenCategorizer : MarshalByRefObject
|
||||
{
|
||||
private readonly TokenizerService _tokenizer;
|
||||
|
||||
public object CurrentState => _tokenizer.CurrentState;
|
||||
|
||||
public SourceLocation CurrentPosition => _tokenizer.CurrentPosition;
|
||||
|
||||
public bool IsRestartable => _tokenizer.IsRestartable;
|
||||
|
||||
public ErrorSink ErrorSink
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tokenizer.ErrorSink;
|
||||
}
|
||||
set
|
||||
{
|
||||
_tokenizer.ErrorSink = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal TokenCategorizer(TokenizerService tokenizer)
|
||||
{
|
||||
_tokenizer = tokenizer;
|
||||
}
|
||||
|
||||
public void Initialize(object state, ScriptSource scriptSource, SourceLocation initialLocation)
|
||||
{
|
||||
_tokenizer.Initialize(state, scriptSource.SourceUnit.GetReader(), scriptSource.SourceUnit, initialLocation);
|
||||
}
|
||||
|
||||
public TokenInfo ReadToken()
|
||||
{
|
||||
return _tokenizer.ReadToken();
|
||||
}
|
||||
|
||||
public bool SkipToken()
|
||||
{
|
||||
return _tokenizer.SkipToken();
|
||||
}
|
||||
|
||||
public IEnumerable<TokenInfo> ReadTokens(int characterCount)
|
||||
{
|
||||
return _tokenizer.ReadTokens(characterCount);
|
||||
}
|
||||
|
||||
public bool SkipTokens(int characterCount)
|
||||
{
|
||||
return _tokenizer.SkipTokens(characterCount);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
|
||||
public override object InitializeLifetimeService()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
33
AspClassic.Scripting/IAttributesCollection.cs
Normal file
33
AspClassic.Scripting/IAttributesCollection.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public interface IAttributesCollection : IEnumerable<KeyValuePair<object, object>>, IEnumerable
|
||||
{
|
||||
object this[SymbolId name] { get; set; }
|
||||
|
||||
IDictionary<SymbolId, object> SymbolAttributes { get; }
|
||||
|
||||
int Count { get; }
|
||||
|
||||
ICollection<object> Keys { get; }
|
||||
|
||||
void Add(SymbolId name, object value);
|
||||
|
||||
bool TryGetValue(SymbolId name, out object value);
|
||||
|
||||
bool Remove(SymbolId name);
|
||||
|
||||
bool ContainsKey(SymbolId name);
|
||||
|
||||
void AddObjectKey(object name, object value);
|
||||
|
||||
bool TryGetObjectValue(object name, out object value);
|
||||
|
||||
bool RemoveObjectKey(object name);
|
||||
|
||||
bool ContainsObjectKey(object name);
|
||||
|
||||
IDictionary<object, object> AsObjectKeyedDictionary();
|
||||
}
|
12
AspClassic.Scripting/IScopeVariable.cs
Normal file
12
AspClassic.Scripting/IScopeVariable.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public interface IScopeVariable
|
||||
{
|
||||
bool HasValue { get; }
|
||||
|
||||
bool TryGetValue(out dynamic value);
|
||||
|
||||
void SetValue(object value);
|
||||
|
||||
bool DeleteValue();
|
||||
}
|
8
AspClassic.Scripting/IWeakReferencable.cs
Normal file
8
AspClassic.Scripting/IWeakReferencable.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
internal interface IWeakReferencable
|
||||
{
|
||||
WeakReference WeakReference { get; }
|
||||
}
|
27
AspClassic.Scripting/InvalidImplementationException.cs
Normal file
27
AspClassic.Scripting/InvalidImplementationException.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class InvalidImplementationException : Exception
|
||||
{
|
||||
public InvalidImplementationException()
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidImplementationException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidImplementationException(string message, Exception e)
|
||||
: base(message, e)
|
||||
{
|
||||
}
|
||||
|
||||
protected InvalidImplementationException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
}
|
131
AspClassic.Scripting/LanguageOptions.cs
Normal file
131
AspClassic.Scripting/LanguageOptions.cs
Normal file
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class LanguageOptions
|
||||
{
|
||||
private bool _exceptionDetail;
|
||||
|
||||
private bool _showClrExceptions;
|
||||
|
||||
private bool _interpretedMode;
|
||||
|
||||
private readonly bool _perfStats;
|
||||
|
||||
private readonly bool _noAdaptiveCompilation;
|
||||
|
||||
private readonly int _compilationThreshold;
|
||||
|
||||
private readonly ReadOnlyCollection<string> _searchPaths;
|
||||
|
||||
protected static readonly ReadOnlyCollection<string> EmptyStringCollection = new ReadOnlyCollection<string>(ArrayUtils.EmptyStrings);
|
||||
|
||||
public bool NoAdaptiveCompilation => _noAdaptiveCompilation;
|
||||
|
||||
public int CompilationThreshold => _compilationThreshold;
|
||||
|
||||
[Obsolete("No longer used.")]
|
||||
public bool InterpretedMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _interpretedMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
_interpretedMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ExceptionDetail
|
||||
{
|
||||
get
|
||||
{
|
||||
return _exceptionDetail;
|
||||
}
|
||||
set
|
||||
{
|
||||
_exceptionDetail = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowClrExceptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showClrExceptions;
|
||||
}
|
||||
set
|
||||
{
|
||||
_showClrExceptions = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool PerfStats => _perfStats;
|
||||
|
||||
public ReadOnlyCollection<string> SearchPaths => _searchPaths;
|
||||
|
||||
public LanguageOptions()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public LanguageOptions(IDictionary<string, object> options)
|
||||
{
|
||||
_interpretedMode = GetOption(options, "InterpretedMode", defaultValue: false);
|
||||
_exceptionDetail = GetOption(options, "ExceptionDetail", defaultValue: false);
|
||||
_showClrExceptions = GetOption(options, "ShowClrExceptions", defaultValue: false);
|
||||
_perfStats = GetOption(options, "PerfStats", defaultValue: false);
|
||||
_noAdaptiveCompilation = GetOption(options, "NoAdaptiveCompilation", defaultValue: false);
|
||||
_compilationThreshold = GetOption(options, "CompilationThreshold", -1);
|
||||
_searchPaths = GetSearchPathsOption(options) ?? new ReadOnlyCollection<string>(new string[0]);
|
||||
}
|
||||
|
||||
public static T GetOption<T>(IDictionary<string, object> options, string name, T defaultValue)
|
||||
{
|
||||
if (options != null && options.TryGetValue(name, out var value))
|
||||
{
|
||||
if (value is T)
|
||||
{
|
||||
return (T)value;
|
||||
}
|
||||
return (T)Convert.ChangeType(value, typeof(T), Thread.CurrentThread.CurrentCulture);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static ReadOnlyCollection<string> GetStringCollectionOption(IDictionary<string, object> options, string name, params char[] separators)
|
||||
{
|
||||
if (options == null || !options.TryGetValue(name, out var value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (value is ICollection<string> collection)
|
||||
{
|
||||
foreach (string item in collection)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentException($"Invalid value for option {name}: collection shouldn't containt null items");
|
||||
}
|
||||
}
|
||||
return new ReadOnlyCollection<string>(ArrayUtils.MakeArray(collection));
|
||||
}
|
||||
if (value is string str && separators != null && separators.Length > 0)
|
||||
{
|
||||
return new ReadOnlyCollection<string>(StringUtils.Split(str, separators, int.MaxValue, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
throw new ArgumentException($"Invalid value for option {name}");
|
||||
}
|
||||
|
||||
public static ReadOnlyCollection<string> GetSearchPathsOption(IDictionary<string, object> options)
|
||||
{
|
||||
return GetStringCollectionOption(options, "SearchPaths", Path.PathSeparator);
|
||||
}
|
||||
}
|
12
AspClassic.Scripting/NullErrorSink.cs
Normal file
12
AspClassic.Scripting/NullErrorSink.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
internal sealed class NullErrorSink : ErrorSink
|
||||
{
|
||||
internal NullErrorSink()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Add(SourceUnit source, string message, SourceSpan span, int errorCode, Severity severity)
|
||||
{
|
||||
}
|
||||
}
|
8
AspClassic.Scripting/ParamDictionaryAttribute.cs
Normal file
8
AspClassic.Scripting/ParamDictionaryAttribute.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class ParamDictionaryAttribute : Attribute
|
||||
{
|
||||
}
|
232
AspClassic.Scripting/PlatformAdaptationLayer.cs
Normal file
232
AspClassic.Scripting/PlatformAdaptationLayer.cs
Normal file
|
@ -0,0 +1,232 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class PlatformAdaptationLayer
|
||||
{
|
||||
public static readonly PlatformAdaptationLayer Default = new PlatformAdaptationLayer();
|
||||
|
||||
public static readonly bool IsCompactFramework = Environment.OSVersion.Platform == PlatformID.WinCE || Environment.OSVersion.Platform == PlatformID.Xbox;
|
||||
|
||||
private static bool IsSingleRootFileSystem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
{
|
||||
return Environment.OSVersion.Platform == PlatformID.MacOSX;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual StringComparer PathComparer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Environment.OSVersion.Platform != PlatformID.Unix)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase;
|
||||
}
|
||||
return StringComparer.Ordinal;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string CurrentDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return Directory.GetCurrentDirectory();
|
||||
}
|
||||
set
|
||||
{
|
||||
Directory.SetCurrentDirectory(value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Assembly LoadAssembly(string name)
|
||||
{
|
||||
return Assembly.Load(name);
|
||||
}
|
||||
|
||||
public virtual Assembly LoadAssemblyFromPath(string path)
|
||||
{
|
||||
return Assembly.LoadFile(path);
|
||||
}
|
||||
|
||||
public virtual void TerminateScriptExecution(int exitCode)
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
}
|
||||
|
||||
public virtual bool FileExists(string path)
|
||||
{
|
||||
return File.Exists(path);
|
||||
}
|
||||
|
||||
public virtual bool DirectoryExists(string path)
|
||||
{
|
||||
return Directory.Exists(path);
|
||||
}
|
||||
|
||||
public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
return new FileStream(path, mode, access, share);
|
||||
}
|
||||
|
||||
public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
|
||||
{
|
||||
return new FileStream(path, mode, access, share, bufferSize);
|
||||
}
|
||||
|
||||
public virtual Stream OpenInputFileStream(string path)
|
||||
{
|
||||
return new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public virtual Stream OpenOutputFileStream(string path)
|
||||
{
|
||||
return new FileStream(path, FileMode.Create, FileAccess.Write);
|
||||
}
|
||||
|
||||
public virtual void DeleteFile(string path, bool deleteReadOnly)
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(path);
|
||||
if (deleteReadOnly && fileInfo.IsReadOnly)
|
||||
{
|
||||
fileInfo.IsReadOnly = false;
|
||||
}
|
||||
fileInfo.Delete();
|
||||
}
|
||||
|
||||
[Obsolete("Use GetFileSystemEntries instead")]
|
||||
public virtual string[] GetFiles(string path, string searchPattern)
|
||||
{
|
||||
return Directory.GetFiles(path, searchPattern);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetFileSystemEntries instead")]
|
||||
public virtual string[] GetDirectories(string path, string searchPattern)
|
||||
{
|
||||
return Directory.GetDirectories(path, searchPattern);
|
||||
}
|
||||
|
||||
public string[] GetFileSystemEntries(string path, string searchPattern)
|
||||
{
|
||||
return GetFileSystemEntries(path, searchPattern, includeFiles: true, includeDirectories: true);
|
||||
}
|
||||
|
||||
public virtual string[] GetFileSystemEntries(string path, string searchPattern, bool includeFiles, bool includeDirectories)
|
||||
{
|
||||
if (includeFiles && includeDirectories)
|
||||
{
|
||||
return ArrayUtils.AppendRange(GetDirectories(path, searchPattern), GetFiles(path, searchPattern));
|
||||
}
|
||||
if (includeFiles)
|
||||
{
|
||||
return GetFiles(path, searchPattern);
|
||||
}
|
||||
if (includeDirectories)
|
||||
{
|
||||
return GetDirectories(path, searchPattern);
|
||||
}
|
||||
return ArrayUtils.EmptyStrings;
|
||||
}
|
||||
|
||||
public virtual string GetFullPath(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Path.GetFullPath(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw Error.InvalidPath();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string CombinePaths(string path1, string path2)
|
||||
{
|
||||
return Path.Combine(path1, path2);
|
||||
}
|
||||
|
||||
public virtual string GetFileName(string path)
|
||||
{
|
||||
return Path.GetFileName(path);
|
||||
}
|
||||
|
||||
public virtual string GetDirectoryName(string path)
|
||||
{
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
public virtual string GetExtension(string path)
|
||||
{
|
||||
return Path.GetExtension(path);
|
||||
}
|
||||
|
||||
public virtual string GetFileNameWithoutExtension(string path)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(path);
|
||||
}
|
||||
|
||||
public virtual bool IsAbsolutePath(string path)
|
||||
{
|
||||
if (IsSingleRootFileSystem)
|
||||
{
|
||||
return Path.IsPathRooted(path);
|
||||
}
|
||||
string pathRoot = Path.GetPathRoot(path);
|
||||
if (!pathRoot.EndsWith(":\\"))
|
||||
{
|
||||
return pathRoot.EndsWith(":/");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void CreateDirectory(string path)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public virtual void DeleteDirectory(string path, bool recursive)
|
||||
{
|
||||
Directory.Delete(path, recursive);
|
||||
}
|
||||
|
||||
public virtual void MoveFileSystemEntry(string sourcePath, string destinationPath)
|
||||
{
|
||||
Directory.Move(sourcePath, destinationPath);
|
||||
}
|
||||
|
||||
public virtual string GetEnvironmentVariable(string key)
|
||||
{
|
||||
return Environment.GetEnvironmentVariable(key);
|
||||
}
|
||||
|
||||
public virtual void SetEnvironmentVariable(string key, string value)
|
||||
{
|
||||
if (value != null && value.Length == 0)
|
||||
{
|
||||
if (!NativeMethods.SetEnvironmentVariable(key, value))
|
||||
{
|
||||
throw new ExternalException("SetEnvironmentVariable failed", Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.SetEnvironmentVariable(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IDictionary GetEnvironmentVariables()
|
||||
{
|
||||
return Environment.GetEnvironmentVariables();
|
||||
}
|
||||
}
|
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();
|
||||
}
|
||||
}
|
182
AspClassic.Scripting/ScopeStorage.cs
Normal file
182
AspClassic.Scripting/ScopeStorage.cs
Normal file
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public sealed class ScopeStorage : IDynamicMetaObjectProvider
|
||||
{
|
||||
private class Meta : DynamicMetaObject
|
||||
{
|
||||
public new ScopeStorage Value => (ScopeStorage)base.Value;
|
||||
|
||||
public Meta(Expression parameter, ScopeStorage storage)
|
||||
: base(parameter, BindingRestrictions.Empty, storage)
|
||||
{
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
|
||||
{
|
||||
return DynamicTryGetValue(binder.Name, binder.IgnoreCase, binder.FallbackGetMember(this).Expression, (Expression tmp) => tmp);
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
|
||||
{
|
||||
return DynamicTryGetValue(binder.Name, binder.IgnoreCase, binder.FallbackInvokeMember(this, args).Expression, (Expression tmp) => binder.FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression);
|
||||
}
|
||||
|
||||
private DynamicMetaObject DynamicTryGetValue(string name, bool ignoreCase, Expression fallback, Func<Expression, Expression> resultOp)
|
||||
{
|
||||
IScopeVariable variable = Value.GetVariable(name, ignoreCase);
|
||||
ParameterExpression parameterExpression = Expression.Parameter(typeof(object));
|
||||
return new DynamicMetaObject(Expression.Block(new ParameterExpression[1] { parameterExpression }, Expression.Condition(Expression.Call(Variable(variable), variable.GetType().GetMethod("TryGetValue"), parameterExpression), ExpressionUtils.Convert(resultOp(parameterExpression), typeof(object)), ExpressionUtils.Convert(fallback, typeof(object)))), BindingRestrictions.GetInstanceRestriction(base.Expression, Value));
|
||||
}
|
||||
|
||||
private static Expression Variable(IScopeVariable variable)
|
||||
{
|
||||
return Expression.Convert(Expression.Property(Expression.Constant(((IWeakReferencable)variable).WeakReference), typeof(WeakReference).GetProperty("Target")), variable.GetType());
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
|
||||
{
|
||||
IScopeVariable variable = Value.GetVariable(binder.Name, binder.IgnoreCase);
|
||||
Expression expression = ExpressionUtils.Convert(value.Expression, typeof(object));
|
||||
return new DynamicMetaObject(Expression.Block(Expression.Call(Variable(variable), variable.GetType().GetMethod("SetValue"), expression), expression), BindingRestrictions.GetInstanceRestriction(base.Expression, Value));
|
||||
}
|
||||
|
||||
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder)
|
||||
{
|
||||
IScopeVariable variable = Value.GetVariable(binder.Name, binder.IgnoreCase);
|
||||
return new DynamicMetaObject(Expression.Condition(Expression.Call(Variable(variable), variable.GetType().GetMethod("DeleteValue")), Expression.Default(binder.ReturnType), binder.FallbackDeleteMember(this).Expression), BindingRestrictions.GetInstanceRestriction(base.Expression, Value));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetDynamicMemberNames()
|
||||
{
|
||||
return Value.GetMemberNames();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, ScopeVariableIgnoreCase> _storage = new Dictionary<string, ScopeVariableIgnoreCase>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public dynamic this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetValue(index, ignoreCase: false);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(index, ignoreCase: false, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public dynamic GetValue(string name, bool ignoreCase)
|
||||
{
|
||||
if (GetVariable(name, ignoreCase).TryGetValue(out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
throw new KeyNotFoundException("no value");
|
||||
}
|
||||
|
||||
public bool TryGetValue(string name, bool ignoreCase, out dynamic value)
|
||||
{
|
||||
if (HasVariable(name) && GetVariable(name, ignoreCase).TryGetValue(out var value2))
|
||||
{
|
||||
value = value2;
|
||||
return true;
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetValue(string name, bool ignoreCase, object value)
|
||||
{
|
||||
GetVariable(name, ignoreCase).SetValue(value);
|
||||
}
|
||||
|
||||
public bool DeleteValue(string name, bool ignoreCase)
|
||||
{
|
||||
if (!HasVariable(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return GetVariable(name, ignoreCase).DeleteValue();
|
||||
}
|
||||
|
||||
public bool HasValue(string name, bool ignoreCase)
|
||||
{
|
||||
if (!HasVariable(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return GetVariable(name, ignoreCase).HasValue;
|
||||
}
|
||||
|
||||
public IScopeVariable GetVariable(string name, bool ignoreCase)
|
||||
{
|
||||
if (ignoreCase)
|
||||
{
|
||||
return GetVariableIgnoreCase(name);
|
||||
}
|
||||
return GetVariable(name);
|
||||
}
|
||||
|
||||
public ScopeVariable GetVariable(string name)
|
||||
{
|
||||
return GetVariableIgnoreCase(name).GetCaseSensitiveStorage(name);
|
||||
}
|
||||
|
||||
public ScopeVariableIgnoreCase GetVariableIgnoreCase(string name)
|
||||
{
|
||||
lock (_storage)
|
||||
{
|
||||
if (!_storage.TryGetValue(name, out var value))
|
||||
{
|
||||
value = (_storage[name] = new ScopeVariableIgnoreCase(name));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<string> GetMemberNames()
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
lock (_storage)
|
||||
{
|
||||
foreach (ScopeVariableIgnoreCase value in _storage.Values)
|
||||
{
|
||||
value.AddNames(list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<string, object>> GetItems()
|
||||
{
|
||||
List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
|
||||
lock (_storage)
|
||||
{
|
||||
foreach (ScopeVariableIgnoreCase value in _storage.Values)
|
||||
{
|
||||
value.AddItems(list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasVariable(string name)
|
||||
{
|
||||
lock (_storage)
|
||||
{
|
||||
return _storage.ContainsKey(name);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new Meta(parameter, this);
|
||||
}
|
||||
}
|
53
AspClassic.Scripting/ScopeVariable.cs
Normal file
53
AspClassic.Scripting/ScopeVariable.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public sealed class ScopeVariable : IScopeVariable, IWeakReferencable
|
||||
{
|
||||
private object _value;
|
||||
|
||||
private WeakReference _weakref;
|
||||
|
||||
private static readonly object _novalue = new object();
|
||||
|
||||
public bool HasValue => _value != _novalue;
|
||||
|
||||
public WeakReference WeakReference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_weakref == null)
|
||||
{
|
||||
_weakref = new WeakReference(this);
|
||||
}
|
||||
return _weakref;
|
||||
}
|
||||
}
|
||||
|
||||
internal ScopeVariable()
|
||||
{
|
||||
_value = _novalue;
|
||||
}
|
||||
|
||||
public bool TryGetValue(out dynamic value)
|
||||
{
|
||||
value = _value;
|
||||
if ((object)value != _novalue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetValue(object value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public bool DeleteValue()
|
||||
{
|
||||
return Interlocked.Exchange(ref _value, _novalue) != _novalue;
|
||||
}
|
||||
}
|
175
AspClassic.Scripting/ScopeVariableIgnoreCase.cs
Normal file
175
AspClassic.Scripting/ScopeVariableIgnoreCase.cs
Normal file
|
@ -0,0 +1,175 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public sealed class ScopeVariableIgnoreCase : IScopeVariable, IWeakReferencable
|
||||
{
|
||||
private readonly string _firstCasing;
|
||||
|
||||
private readonly ScopeVariable _firstVariable;
|
||||
|
||||
private WeakReference _weakref;
|
||||
|
||||
private Dictionary<string, ScopeVariable> _overflow;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_firstVariable.HasValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (_overflow != null)
|
||||
{
|
||||
lock (_overflow)
|
||||
{
|
||||
foreach (KeyValuePair<string, ScopeVariable> item in _overflow)
|
||||
{
|
||||
if (item.Value.HasValue)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public WeakReference WeakReference
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_weakref == null)
|
||||
{
|
||||
_weakref = new WeakReference(this);
|
||||
}
|
||||
return _weakref;
|
||||
}
|
||||
}
|
||||
|
||||
internal ScopeVariableIgnoreCase(string casing)
|
||||
{
|
||||
_firstCasing = casing;
|
||||
_firstVariable = new ScopeVariable();
|
||||
}
|
||||
|
||||
public bool TryGetValue(out dynamic value)
|
||||
{
|
||||
if (_firstVariable.TryGetValue(out var value2))
|
||||
{
|
||||
value = value2;
|
||||
return true;
|
||||
}
|
||||
if (_overflow != null)
|
||||
{
|
||||
lock (_overflow)
|
||||
{
|
||||
foreach (KeyValuePair<string, ScopeVariable> item in _overflow)
|
||||
{
|
||||
if (item.Value.TryGetValue(out value2))
|
||||
{
|
||||
value = value2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetValue(object value)
|
||||
{
|
||||
_firstVariable.SetValue(value);
|
||||
}
|
||||
|
||||
public bool DeleteValue()
|
||||
{
|
||||
bool flag = _firstVariable.DeleteValue();
|
||||
if (_overflow != null)
|
||||
{
|
||||
lock (_overflow)
|
||||
{
|
||||
foreach (KeyValuePair<string, ScopeVariable> item in _overflow)
|
||||
{
|
||||
flag = item.Value.DeleteValue() || flag;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
internal ScopeVariable GetCaseSensitiveStorage(string name)
|
||||
{
|
||||
if (name == _firstCasing)
|
||||
{
|
||||
return _firstVariable;
|
||||
}
|
||||
return GetStorageSlow(name);
|
||||
}
|
||||
|
||||
internal void AddNames(List<string> list)
|
||||
{
|
||||
if (_firstVariable.HasValue)
|
||||
{
|
||||
list.Add(_firstCasing);
|
||||
}
|
||||
if (_overflow == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_overflow)
|
||||
{
|
||||
foreach (KeyValuePair<string, ScopeVariable> item in _overflow)
|
||||
{
|
||||
if (item.Value.HasValue)
|
||||
{
|
||||
list.Add(item.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddItems(List<KeyValuePair<string, object>> list)
|
||||
{
|
||||
if (_firstVariable.TryGetValue(out var value))
|
||||
{
|
||||
list.Add(new KeyValuePair<string, object>(_firstCasing, value));
|
||||
}
|
||||
if (_overflow == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_overflow)
|
||||
{
|
||||
foreach (KeyValuePair<string, ScopeVariable> item in _overflow)
|
||||
{
|
||||
if (item.Value.TryGetValue(out value))
|
||||
{
|
||||
list.Add(new KeyValuePair<string, object>(item.Key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScopeVariable GetStorageSlow(string name)
|
||||
{
|
||||
if (_overflow == null)
|
||||
{
|
||||
Interlocked.CompareExchange(ref _overflow, new Dictionary<string, ScopeVariable>(), null);
|
||||
}
|
||||
lock (_overflow)
|
||||
{
|
||||
if (!_overflow.TryGetValue(name, out var value))
|
||||
{
|
||||
value = (_overflow[name] = new ScopeVariable());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
36
AspClassic.Scripting/ScriptCode.cs
Normal file
36
AspClassic.Scripting/ScriptCode.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public abstract class ScriptCode
|
||||
{
|
||||
private readonly SourceUnit _sourceUnit;
|
||||
|
||||
public LanguageContext LanguageContext => _sourceUnit.LanguageContext;
|
||||
|
||||
public SourceUnit SourceUnit => _sourceUnit;
|
||||
|
||||
protected ScriptCode(SourceUnit sourceUnit)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(sourceUnit, "sourceUnit");
|
||||
_sourceUnit = sourceUnit;
|
||||
}
|
||||
|
||||
public virtual Scope CreateScope()
|
||||
{
|
||||
return new Scope();
|
||||
}
|
||||
|
||||
public virtual object Run()
|
||||
{
|
||||
return Run(CreateScope());
|
||||
}
|
||||
|
||||
public abstract object Run(Scope scope);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ScriptCode '{SourceUnit.Path}' from {LanguageContext.GetType().Name}";
|
||||
}
|
||||
}
|
10
AspClassic.Scripting/ScriptCodeParseResult.cs
Normal file
10
AspClassic.Scripting/ScriptCodeParseResult.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public enum ScriptCodeParseResult
|
||||
{
|
||||
Complete,
|
||||
Empty,
|
||||
Invalid,
|
||||
IncompleteToken,
|
||||
IncompleteStatement
|
||||
}
|
9
AspClassic.Scripting/Severity.cs
Normal file
9
AspClassic.Scripting/Severity.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public enum Severity
|
||||
{
|
||||
Ignore,
|
||||
Warning,
|
||||
Error,
|
||||
FatalError
|
||||
}
|
15
AspClassic.Scripting/SourceCodeKind.cs
Normal file
15
AspClassic.Scripting/SourceCodeKind.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public enum SourceCodeKind
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
Unspecified,
|
||||
Expression,
|
||||
Statements,
|
||||
SingleStatement,
|
||||
File,
|
||||
InteractiveCode,
|
||||
AutoDetect
|
||||
}
|
21
AspClassic.Scripting/SourceCodePropertiesUtils.cs
Normal file
21
AspClassic.Scripting/SourceCodePropertiesUtils.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public static class SourceCodePropertiesUtils
|
||||
{
|
||||
public static bool IsCompleteOrInvalid(ScriptCodeParseResult props, bool allowIncompleteStatement)
|
||||
{
|
||||
switch (props)
|
||||
{
|
||||
default:
|
||||
if (!allowIncompleteStatement)
|
||||
{
|
||||
return props != ScriptCodeParseResult.IncompleteStatement;
|
||||
}
|
||||
return true;
|
||||
case ScriptCodeParseResult.IncompleteToken:
|
||||
return false;
|
||||
case ScriptCodeParseResult.Invalid:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
95
AspClassic.Scripting/SourceCodeReader.cs
Normal file
95
AspClassic.Scripting/SourceCodeReader.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public class SourceCodeReader : TextReader
|
||||
{
|
||||
public new static readonly SourceCodeReader Null = new SourceCodeReader(TextReader.Null, null);
|
||||
|
||||
private readonly TextReader _textReader;
|
||||
|
||||
private readonly Encoding _encoding;
|
||||
|
||||
public Encoding Encoding => _encoding;
|
||||
|
||||
public TextReader BaseReader => _textReader;
|
||||
|
||||
public SourceCodeReader(TextReader textReader, Encoding encoding)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(textReader, "textReader");
|
||||
_encoding = encoding;
|
||||
_textReader = textReader;
|
||||
}
|
||||
|
||||
public override string ReadLine()
|
||||
{
|
||||
return _textReader.ReadLine();
|
||||
}
|
||||
|
||||
public virtual bool SeekLine(int line)
|
||||
{
|
||||
if (line < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("line");
|
||||
}
|
||||
if (line == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int num = 1;
|
||||
while (true)
|
||||
{
|
||||
switch (_textReader.Read())
|
||||
{
|
||||
case 13:
|
||||
if (_textReader.Peek() == 10)
|
||||
{
|
||||
_textReader.Read();
|
||||
}
|
||||
num++;
|
||||
if (num == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
num++;
|
||||
if (num == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string ReadToEnd()
|
||||
{
|
||||
return _textReader.ReadToEnd();
|
||||
}
|
||||
|
||||
public override int Read(char[] buffer, int index, int count)
|
||||
{
|
||||
return _textReader.Read(buffer, index, count);
|
||||
}
|
||||
|
||||
public override int Peek()
|
||||
{
|
||||
return _textReader.Peek();
|
||||
}
|
||||
|
||||
public override int Read()
|
||||
{
|
||||
return _textReader.Read();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_textReader.Dispose();
|
||||
}
|
||||
}
|
153
AspClassic.Scripting/SourceLocation.cs
Normal file
153
AspClassic.Scripting/SourceLocation.cs
Normal file
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public struct SourceLocation
|
||||
{
|
||||
private readonly int _index;
|
||||
|
||||
private readonly int _line;
|
||||
|
||||
private readonly int _column;
|
||||
|
||||
public static readonly SourceLocation None = new SourceLocation(0, 16707566, 0, noChecks: true);
|
||||
|
||||
public static readonly SourceLocation Invalid = new SourceLocation(0, 0, 0, noChecks: true);
|
||||
|
||||
public static readonly SourceLocation MinValue = new SourceLocation(0, 1, 1);
|
||||
|
||||
public int Index => _index;
|
||||
|
||||
public int Line => _line;
|
||||
|
||||
public int Column => _column;
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_line != 0)
|
||||
{
|
||||
return _column != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public SourceLocation(int index, int line, int column)
|
||||
{
|
||||
ValidateLocation(index, line, column);
|
||||
_index = index;
|
||||
_line = line;
|
||||
_column = column;
|
||||
}
|
||||
|
||||
private static void ValidateLocation(int index, int line, int column)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
throw ErrorOutOfRange("index", 0);
|
||||
}
|
||||
if (line < 1)
|
||||
{
|
||||
throw ErrorOutOfRange("line", 1);
|
||||
}
|
||||
if (column < 1)
|
||||
{
|
||||
throw ErrorOutOfRange("column", 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static Exception ErrorOutOfRange(object p0, object p1)
|
||||
{
|
||||
return new ArgumentOutOfRangeException($"{p0} must be greater than or equal to {p1}");
|
||||
}
|
||||
|
||||
private SourceLocation(int index, int line, int column, bool noChecks)
|
||||
{
|
||||
_index = index;
|
||||
_line = line;
|
||||
_column = column;
|
||||
}
|
||||
|
||||
public static bool operator ==(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
if (left._index == right._index && left._line == right._line)
|
||||
{
|
||||
return left._column == right._column;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator !=(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
if (left._index == right._index && left._line == right._line)
|
||||
{
|
||||
return left._column != right._column;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator <(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left._index < right._index;
|
||||
}
|
||||
|
||||
public static bool operator >(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left._index > right._index;
|
||||
}
|
||||
|
||||
public static bool operator <=(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left._index <= right._index;
|
||||
}
|
||||
|
||||
public static bool operator >=(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left._index >= right._index;
|
||||
}
|
||||
|
||||
public static int Compare(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
if (left < right)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (right > left)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is SourceLocation sourceLocation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (sourceLocation._index == _index && sourceLocation._line == _line)
|
||||
{
|
||||
return sourceLocation._column == _column;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_line << 16) ^ _column;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + _line + "," + _column + ")";
|
||||
}
|
||||
|
||||
internal string ToDebugString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "({0},{1},{2})", new object[3] { _index, _line, _column });
|
||||
}
|
||||
}
|
109
AspClassic.Scripting/SourceSpan.cs
Normal file
109
AspClassic.Scripting/SourceSpan.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public struct SourceSpan
|
||||
{
|
||||
private readonly SourceLocation _start;
|
||||
|
||||
private readonly SourceLocation _end;
|
||||
|
||||
public static readonly SourceSpan None = new SourceSpan(SourceLocation.None, SourceLocation.None);
|
||||
|
||||
public static readonly SourceSpan Invalid = new SourceSpan(SourceLocation.Invalid, SourceLocation.Invalid);
|
||||
|
||||
public SourceLocation Start => _start;
|
||||
|
||||
public SourceLocation End => _end;
|
||||
|
||||
public int Length => _end.Index - _start.Index;
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_start.IsValid)
|
||||
{
|
||||
return _end.IsValid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public SourceSpan(SourceLocation start, SourceLocation end)
|
||||
{
|
||||
ValidateLocations(start, end);
|
||||
_start = start;
|
||||
_end = end;
|
||||
}
|
||||
|
||||
private static void ValidateLocations(SourceLocation start, SourceLocation end)
|
||||
{
|
||||
if (start.IsValid && end.IsValid)
|
||||
{
|
||||
if (start > end)
|
||||
{
|
||||
throw new ArgumentException("Start and End must be well ordered");
|
||||
}
|
||||
}
|
||||
else if (start.IsValid || end.IsValid)
|
||||
{
|
||||
throw new ArgumentException("Start and End must both be valid or both invalid");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(SourceSpan left, SourceSpan right)
|
||||
{
|
||||
if (left._start == right._start)
|
||||
{
|
||||
return left._end == right._end;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool operator !=(SourceSpan left, SourceSpan right)
|
||||
{
|
||||
if (!(left._start != right._start))
|
||||
{
|
||||
return left._end != right._end;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is SourceSpan sourceSpan))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_start == sourceSpan._start)
|
||||
{
|
||||
return _end == sourceSpan._end;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
SourceLocation start = _start;
|
||||
string text = start.ToString();
|
||||
SourceLocation end = _end;
|
||||
return text + " - " + end.ToString();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _start.Column ^ (_end.Column << 7) ^ (_start.Line << 14) ^ (_end.Line << 23);
|
||||
}
|
||||
|
||||
internal string ToDebugString()
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0}-{1}", new object[2]
|
||||
{
|
||||
_start.ToDebugString(),
|
||||
_end.ToDebugString()
|
||||
});
|
||||
}
|
||||
}
|
22
AspClassic.Scripting/SourceStringContentProvider.cs
Normal file
22
AspClassic.Scripting/SourceStringContentProvider.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
internal sealed class SourceStringContentProvider : TextContentProvider
|
||||
{
|
||||
private readonly string _code;
|
||||
|
||||
internal SourceStringContentProvider(string code)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(code, "code");
|
||||
_code = code;
|
||||
}
|
||||
|
||||
public override SourceCodeReader GetReader()
|
||||
{
|
||||
return new SourceCodeReader(new StringReader(_code), null);
|
||||
}
|
||||
}
|
237
AspClassic.Scripting/SourceUnit.cs
Normal file
237
AspClassic.Scripting/SourceUnit.cs
Normal file
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[DebuggerDisplay("{_path ?? \"<anonymous>\"}")]
|
||||
public sealed class SourceUnit
|
||||
{
|
||||
private class KeyComparer<T1> : IComparer<KeyValuePair<int, T1>>
|
||||
{
|
||||
public int Compare(KeyValuePair<int, T1> x, KeyValuePair<int, T1> y)
|
||||
{
|
||||
return x.Key - y.Key;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly SourceCodeKind _kind;
|
||||
|
||||
private readonly string _path;
|
||||
|
||||
private readonly LanguageContext _language;
|
||||
|
||||
private readonly TextContentProvider _contentProvider;
|
||||
|
||||
private ScriptCodeParseResult? _parseResult;
|
||||
|
||||
private KeyValuePair<int, int>[] _lineMap;
|
||||
|
||||
public string Path => _path;
|
||||
|
||||
public bool HasPath => _path != null;
|
||||
|
||||
public SourceCodeKind Kind => _kind;
|
||||
|
||||
public SymbolDocumentInfo Document
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_path != null)
|
||||
{
|
||||
return Expression.SymbolDocument(_path, _language.LanguageGuid, _language.VendorGuid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageContext LanguageContext => _language;
|
||||
|
||||
public ScriptCodeParseResult? CodeProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
return _parseResult;
|
||||
}
|
||||
set
|
||||
{
|
||||
_parseResult = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool EmitDebugSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasPath)
|
||||
{
|
||||
return LanguageContext.DomainManager.Configuration.DebugMode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptCodeParseResult GetCodeProperties()
|
||||
{
|
||||
return GetCodeProperties(_language.GetCompilerOptions());
|
||||
}
|
||||
|
||||
public ScriptCodeParseResult GetCodeProperties(CompilerOptions options)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(options, "options");
|
||||
_language.CompileSourceCode(this, options, ErrorSink.Null);
|
||||
return _parseResult ?? ScriptCodeParseResult.Complete;
|
||||
}
|
||||
|
||||
public SourceUnit(LanguageContext context, TextContentProvider contentProvider, string path, SourceCodeKind kind)
|
||||
{
|
||||
_language = context;
|
||||
_contentProvider = contentProvider;
|
||||
_kind = kind;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
public SourceCodeReader GetReader()
|
||||
{
|
||||
return _contentProvider.GetReader();
|
||||
}
|
||||
|
||||
public string[] GetCodeLines(int start, int count)
|
||||
{
|
||||
ContractUtils.Requires(start > 0, "start");
|
||||
ContractUtils.Requires(count > 0, "count");
|
||||
List<string> list = new List<string>(count);
|
||||
using (SourceCodeReader sourceCodeReader = GetReader())
|
||||
{
|
||||
sourceCodeReader.SeekLine(start);
|
||||
while (count > 0)
|
||||
{
|
||||
string text = sourceCodeReader.ReadLine();
|
||||
if (text != null)
|
||||
{
|
||||
list.Add(text);
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public string GetCodeLine(int line)
|
||||
{
|
||||
string[] codeLines = GetCodeLines(line, 1);
|
||||
if (codeLines.Length <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return codeLines[0];
|
||||
}
|
||||
|
||||
public string GetCode()
|
||||
{
|
||||
using SourceCodeReader sourceCodeReader = GetReader();
|
||||
return sourceCodeReader.ReadToEnd();
|
||||
}
|
||||
|
||||
public SourceLocation MakeLocation(int index, int line, int column)
|
||||
{
|
||||
return new SourceLocation(index, MapLine(line), column);
|
||||
}
|
||||
|
||||
public SourceLocation MakeLocation(SourceLocation loc)
|
||||
{
|
||||
return new SourceLocation(loc.Index, MapLine(loc.Line), loc.Column);
|
||||
}
|
||||
|
||||
public int MapLine(int line)
|
||||
{
|
||||
if (_lineMap != null)
|
||||
{
|
||||
int num = BinarySearch(_lineMap, line);
|
||||
int num2 = line - _lineMap[num].Key;
|
||||
line = _lineMap[num].Value + num2;
|
||||
if (line < 1)
|
||||
{
|
||||
line = 1;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private static int BinarySearch<T>(KeyValuePair<int, T>[] array, int line)
|
||||
{
|
||||
int num = Array.BinarySearch(array, new KeyValuePair<int, T>(line, default(T)), new KeyComparer<T>());
|
||||
if (num < 0)
|
||||
{
|
||||
num = ~num - 1;
|
||||
if (num == -1)
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public ScriptCode Compile()
|
||||
{
|
||||
return Compile(ErrorSink.Default);
|
||||
}
|
||||
|
||||
public ScriptCode Compile(ErrorSink errorSink)
|
||||
{
|
||||
return Compile(_language.GetCompilerOptions(), errorSink);
|
||||
}
|
||||
|
||||
public ScriptCode Compile(CompilerOptions options, ErrorSink errorSink)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(errorSink, "errorSink");
|
||||
ContractUtils.RequiresNotNull(options, "options");
|
||||
return _language.CompileSourceCode(this, options, errorSink);
|
||||
}
|
||||
|
||||
public object Execute(Scope scope)
|
||||
{
|
||||
return Execute(scope, ErrorSink.Default);
|
||||
}
|
||||
|
||||
public object Execute(Scope scope, ErrorSink errorSink)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(scope, "scope");
|
||||
ScriptCode scriptCode = Compile(_language.GetCompilerOptions(scope), errorSink);
|
||||
if (scriptCode == null)
|
||||
{
|
||||
throw new SyntaxErrorException();
|
||||
}
|
||||
return scriptCode.Run(scope);
|
||||
}
|
||||
|
||||
public object Execute()
|
||||
{
|
||||
return Compile().Run();
|
||||
}
|
||||
|
||||
public object Execute(ErrorSink errorSink)
|
||||
{
|
||||
return Compile(errorSink).Run();
|
||||
}
|
||||
|
||||
public object Execute(CompilerOptions options, ErrorSink errorSink)
|
||||
{
|
||||
return Compile(options, errorSink).Run();
|
||||
}
|
||||
|
||||
public int ExecuteProgram()
|
||||
{
|
||||
return _language.ExecuteProgram(this);
|
||||
}
|
||||
|
||||
public void SetLineMapping(KeyValuePair<int, int>[] lineMap)
|
||||
{
|
||||
_lineMap = ((lineMap == null || lineMap.Length == 0) ? null : lineMap);
|
||||
}
|
||||
}
|
10
AspClassic.Scripting/StreamContentProvider.cs
Normal file
10
AspClassic.Scripting/StreamContentProvider.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public abstract class StreamContentProvider
|
||||
{
|
||||
public abstract Stream GetStream();
|
||||
}
|
253
AspClassic.Scripting/Strings.cs
Normal file
253
AspClassic.Scripting/Strings.cs
Normal file
|
@ -0,0 +1,253 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
internal static class Strings
|
||||
{
|
||||
internal static string MethodPreconditionViolated => "Method precondition violated";
|
||||
|
||||
internal static string InvalidArgumentValue => "Invalid argument value";
|
||||
|
||||
internal static string NonEmptyStringRequired => "Non-empty string required";
|
||||
|
||||
internal static string NonEmptyCollectionRequired => "Non-empty collection required";
|
||||
|
||||
internal static string MustBeExceptionInstance => "must by an Exception instance";
|
||||
|
||||
internal static string TypeOfTestMustBeBool => "Type of test must be bool";
|
||||
|
||||
internal static string TypeOfExpressionMustBeBool => "Type of the expression must be bool";
|
||||
|
||||
internal static string EmptyStringIsInvalidPath => "Empty string is not a valid path.";
|
||||
|
||||
internal static string InvalidDelegate => "Invalid delegate type (Invoke method not found).";
|
||||
|
||||
internal static string ExpectedStaticProperty => "expected only static property";
|
||||
|
||||
internal static string PropertyDoesNotExist => "Property doesn't exist on the provided type";
|
||||
|
||||
internal static string FieldDoesNotExist => "Field doesn't exist on provided type";
|
||||
|
||||
internal static string TypeDoesNotHaveConstructorForTheSignature => "Type doesn't have constructor with a given signature";
|
||||
|
||||
internal static string TypeDoesNotHaveMethodForName => "Type doesn't have a method with a given name.";
|
||||
|
||||
internal static string TypeDoesNotHaveMethodForNameSignature => "Type doesn't have a method with a given name and signature.";
|
||||
|
||||
internal static string CountCannotBeNegative => "Count must be non-negative.";
|
||||
|
||||
internal static string ArrayTypeMustBeArray => "arrayType must be an array type";
|
||||
|
||||
internal static string MustHaveCodeOrTarget => "Either code or target must be specified.";
|
||||
|
||||
internal static string FirstArgumentMustBeCallSite => "RuleBuilder can only be used with delegates whose first argument is CallSite.";
|
||||
|
||||
internal static string NoInstanceForCall => "no instance for call.";
|
||||
|
||||
internal static string MissingTest => "Missing Test.";
|
||||
|
||||
internal static string MissingTarget => "Missing Target.";
|
||||
|
||||
internal static string FinallyAlreadyDefined => "Finally already defined.";
|
||||
|
||||
internal static string CannotHaveFaultAndFinally => "Can not have fault and finally.";
|
||||
|
||||
internal static string FaultAlreadyDefined => "Fault already defined.";
|
||||
|
||||
internal static string GlobalsMustBeUnique => "Global/top-level local variable names must be unique.";
|
||||
|
||||
internal static string GenNonSerializableBinder => "Generating code from non-serializable CallSiteBinder.";
|
||||
|
||||
internal static string InvalidPath => "Specified path is invalid.";
|
||||
|
||||
internal static string DictionaryNotHashable => "Dictionaries are not hashable.";
|
||||
|
||||
internal static string LanguageRegistered => "language already registered.";
|
||||
|
||||
internal static string MethodOrOperatorNotImplemented => "The method or operation is not implemented.";
|
||||
|
||||
internal static string NoException => "No exception.";
|
||||
|
||||
internal static string AlreadyInitialized => "Already initialized.";
|
||||
|
||||
internal static string MustReturnScopeExtension => "CreateScopeExtension must return a scope extension.";
|
||||
|
||||
internal static string InvalidParamNumForService => "Invalid number of parameters for the service.";
|
||||
|
||||
internal static string CannotChangeNonCachingValue => "Cannot change non-caching value.";
|
||||
|
||||
internal static string NoCodeToCompile => "No code to compile.";
|
||||
|
||||
internal static string QueueEmpty => "Queue empty.";
|
||||
|
||||
internal static string EnumerationNotStarted => "Enumeration has not started. Call MoveNext.";
|
||||
|
||||
internal static string EnumerationFinished => "Enumeration already finished.";
|
||||
|
||||
internal static string InvalidOutputDir => "Invalid output directory.";
|
||||
|
||||
internal static string InvalidAsmNameOrExtension => "Invalid assembly name or file extension.";
|
||||
|
||||
internal static string NoDefaultValue => "No default value for a given type.";
|
||||
|
||||
internal static string UnknownLanguageProviderType => "Specified language provider type is not registered.";
|
||||
|
||||
internal static string CantReadProperty => "can't read from property";
|
||||
|
||||
internal static string CantWriteProperty => "can't write to property";
|
||||
|
||||
private static string FormatString(string format, params object[] args)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, format, args);
|
||||
}
|
||||
|
||||
internal static string InvalidOperation_ContainsGenericParameters(object p0, object p1)
|
||||
{
|
||||
return FormatString("Cannot access member {1} declared on type {0} because the type contains generic parameters.", p0, p1);
|
||||
}
|
||||
|
||||
internal static string MissingType(object p0)
|
||||
{
|
||||
return FormatString("Type '{0}' is missing or cannot be loaded.", p0);
|
||||
}
|
||||
|
||||
internal static string StaticAccessFromInstanceError(object p0, object p1)
|
||||
{
|
||||
return FormatString("static property \"{0}\" of \"{1}\" can only be read through a type, not an instance", p0, p1);
|
||||
}
|
||||
|
||||
internal static string StaticAssignmentFromInstanceError(object p0, object p1)
|
||||
{
|
||||
return FormatString("static property \"{0}\" of \"{1}\" can only be assigned to through a type, not an instance", p0, p1);
|
||||
}
|
||||
|
||||
internal static string TypeParameterIsNotDelegate(object p0)
|
||||
{
|
||||
return FormatString("Type parameter is {0}. Expected a delegate.", p0);
|
||||
}
|
||||
|
||||
internal static string InvalidCast(object p0, object p1)
|
||||
{
|
||||
return FormatString("Cannot cast from type '{0}' to type '{1}", p0, p1);
|
||||
}
|
||||
|
||||
internal static string UnknownMemberType(object p0)
|
||||
{
|
||||
return FormatString("unknown member type: '{0}'. ", p0);
|
||||
}
|
||||
|
||||
internal static string NonGenericWithGenericGroup(object p0)
|
||||
{
|
||||
return FormatString("The operation requires a non-generic type for {0}, but this represents generic types only", p0);
|
||||
}
|
||||
|
||||
internal static string InvalidOperation(object p0)
|
||||
{
|
||||
return FormatString("Invalid operation: '{0}'", p0);
|
||||
}
|
||||
|
||||
internal static string CantCreateDefaultTypeFor(object p0)
|
||||
{
|
||||
return FormatString("Cannot create default value for type {0}.", p0);
|
||||
}
|
||||
|
||||
internal static string UnhandledConvert(object p0)
|
||||
{
|
||||
return FormatString("Unhandled convert: {0}", p0);
|
||||
}
|
||||
|
||||
internal static string NoCallableMethods(object p0, object p1)
|
||||
{
|
||||
return FormatString("{0}.{1} has no publiclly visible method.", p0, p1);
|
||||
}
|
||||
|
||||
internal static string ExtensionMustBePublic(object p0)
|
||||
{
|
||||
return FormatString("Extension type {0} must be public.", p0);
|
||||
}
|
||||
|
||||
internal static string InvalidArgumentType(object p0, object p1)
|
||||
{
|
||||
return FormatString("Invalid type of argument {0}; expecting {1}.", p0, p1);
|
||||
}
|
||||
|
||||
internal static string FieldReadonly(object p0)
|
||||
{
|
||||
return FormatString("Field {0} is read-only", p0);
|
||||
}
|
||||
|
||||
internal static string PropertyReadonly(object p0)
|
||||
{
|
||||
return FormatString("Property {0} is read-only", p0);
|
||||
}
|
||||
|
||||
internal static string UnexpectedEvent(object p0, object p1, object p2, object p3)
|
||||
{
|
||||
return FormatString("Expected event from {0}.{1}, got event from {2}.{3}.", p0, p1, p2, p3);
|
||||
}
|
||||
|
||||
internal static string ExpectedBoundEvent(object p0)
|
||||
{
|
||||
return FormatString("expected bound event, got {0}.", p0);
|
||||
}
|
||||
|
||||
internal static string UnexpectedType(object p0, object p1)
|
||||
{
|
||||
return FormatString("Expected type {0}, got {1}.", p0, p1);
|
||||
}
|
||||
|
||||
internal static string MemberWriteOnly(object p0)
|
||||
{
|
||||
return FormatString("can only write to member {0}.", p0);
|
||||
}
|
||||
|
||||
internal static string InvalidStreamType(object p0)
|
||||
{
|
||||
return FormatString("Invalid stream type: {0}.", p0);
|
||||
}
|
||||
|
||||
internal static string CantAddCasing(object p0)
|
||||
{
|
||||
return FormatString("can't add another casing for identifier {0}", p0);
|
||||
}
|
||||
|
||||
internal static string CantAddIdentifier(object p0)
|
||||
{
|
||||
return FormatString("can't add new identifier {0}", p0);
|
||||
}
|
||||
|
||||
internal static string InvalidCtorImplementation(object p0, object p1)
|
||||
{
|
||||
return FormatString("Type '{0}' doesn't provide a suitable public constructor or its implementation is faulty: {1}", p0, p1);
|
||||
}
|
||||
|
||||
internal static string CanotEmitConstant(object p0, object p1)
|
||||
{
|
||||
return FormatString("Cannot emit constant {0} ({1})", p0, p1);
|
||||
}
|
||||
|
||||
internal static string NoImplicitCast(object p0, object p1)
|
||||
{
|
||||
return FormatString("No implicit cast from {0} to {1}", p0, p1);
|
||||
}
|
||||
|
||||
internal static string NoExplicitCast(object p0, object p1)
|
||||
{
|
||||
return FormatString("No explicit cast from {0} to {1}", p0, p1);
|
||||
}
|
||||
|
||||
internal static string NameNotDefined(object p0)
|
||||
{
|
||||
return FormatString("name '{0}' not defined", p0);
|
||||
}
|
||||
|
||||
internal static string IllegalNew_GenericParams(object p0)
|
||||
{
|
||||
return FormatString("Cannot create instance of {0} because it contains generic parameters", p0);
|
||||
}
|
||||
|
||||
internal static string VerificationException(object p0, object p1, object p2)
|
||||
{
|
||||
return FormatString("Non-verifiable assembly generated: {0}:\nAssembly preserved as {1}\nError text:\n{2}\n", p0, p1, p2);
|
||||
}
|
||||
}
|
130
AspClassic.Scripting/SymbolId.cs
Normal file
130
AspClassic.Scripting/SymbolId.cs
Normal file
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public struct SymbolId : ISerializable, IComparable, IComparable<SymbolId>, IEquatable<SymbolId>
|
||||
{
|
||||
public const int EmptyId = 0;
|
||||
|
||||
public const int InvalidId = -1;
|
||||
|
||||
private readonly int _id;
|
||||
|
||||
public static readonly SymbolId Empty = new SymbolId(0);
|
||||
|
||||
public static readonly SymbolId[] EmptySymbols = new SymbolId[0];
|
||||
|
||||
public static readonly SymbolId Invalid = new SymbolId(-1);
|
||||
|
||||
public int Id => _id;
|
||||
|
||||
public SymbolId CaseInsensitiveIdentifier => new SymbolId(_id & 0xFFFFFF);
|
||||
|
||||
public int CaseInsensitiveId => _id & 0xFFFFFF;
|
||||
|
||||
public bool IsCaseInsensitive => (_id & -16777216) == 0;
|
||||
|
||||
public bool IsEmpty => _id == 0;
|
||||
|
||||
public bool IsInvalid => _id == -1;
|
||||
|
||||
public SymbolId(int value)
|
||||
{
|
||||
_id = value;
|
||||
}
|
||||
|
||||
public SymbolId(SymbolId value)
|
||||
{
|
||||
_id = value._id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is SymbolId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals((SymbolId)obj);
|
||||
}
|
||||
|
||||
public bool Equals(SymbolId other)
|
||||
{
|
||||
if (_id == other._id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (IsCaseInsensitive || other.IsCaseInsensitive)
|
||||
{
|
||||
return (_id & 0xFFFFFF) == (other._id & 0xFFFFFF);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _id & 0xFFFFFF;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return SymbolTable.IdToString(this);
|
||||
}
|
||||
|
||||
public static explicit operator SymbolId(string s)
|
||||
{
|
||||
return SymbolTable.StringToId(s);
|
||||
}
|
||||
|
||||
public static bool operator ==(SymbolId a, SymbolId b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(SymbolId a, SymbolId b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator <(SymbolId a, SymbolId b)
|
||||
{
|
||||
return a.CompareTo(b) < 0;
|
||||
}
|
||||
|
||||
public static bool operator >(SymbolId a, SymbolId b)
|
||||
{
|
||||
return a.CompareTo(b) > 0;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (!(obj is SymbolId))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return CompareTo((SymbolId)obj);
|
||||
}
|
||||
|
||||
public int CompareTo(SymbolId other)
|
||||
{
|
||||
string text = SymbolTable.IdToString(this);
|
||||
string strB = SymbolTable.IdToString(other);
|
||||
return text.CompareTo(strB);
|
||||
}
|
||||
|
||||
private SymbolId(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(info, "info");
|
||||
_id = SymbolTable.StringToId(info.GetString("symbolName"))._id;
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(info, "info");
|
||||
info.AddValue("symbolName", SymbolTable.IdToString(this));
|
||||
}
|
||||
}
|
162
AspClassic.Scripting/SymbolTable.cs
Normal file
162
AspClassic.Scripting/SymbolTable.cs
Normal file
|
@ -0,0 +1,162 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
public static class SymbolTable
|
||||
{
|
||||
private const int InitialTableSize = 256;
|
||||
|
||||
internal const int CaseVersionMask = -16777216;
|
||||
|
||||
internal const int CaseVersionIncrement = 16777216;
|
||||
|
||||
private static readonly object _lockObj = new object();
|
||||
|
||||
private static readonly Dictionary<string, int> _idDict = new Dictionary<string, int>(256);
|
||||
|
||||
private static readonly Dictionary<string, int> _invariantDict = new Dictionary<string, int>(256, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static readonly Dictionary<int, string> _fieldDict = CreateFieldDictionary();
|
||||
|
||||
private static int _nextCaseInsensitiveId = 1;
|
||||
|
||||
private static Dictionary<int, string> CreateFieldDictionary()
|
||||
{
|
||||
Dictionary<int, string> dictionary = new Dictionary<int, string>(256);
|
||||
dictionary[0] = null;
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public static SymbolId StringToId(string value)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(value, "value");
|
||||
int value2;
|
||||
lock (_lockObj)
|
||||
{
|
||||
if (!_idDict.TryGetValue(value, out value2))
|
||||
{
|
||||
if (!_invariantDict.TryGetValue(value, out value2))
|
||||
{
|
||||
if (_nextCaseInsensitiveId == 16777215)
|
||||
{
|
||||
throw Error.CantAddIdentifier(value);
|
||||
}
|
||||
value2 = _nextCaseInsensitiveId++ | 0x1000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((uint)value2 & -16777216) == -16777216)
|
||||
{
|
||||
throw Error.CantAddCasing(value);
|
||||
}
|
||||
value2 += 16777216;
|
||||
}
|
||||
_invariantDict[value] = value2;
|
||||
_idDict[value] = value2;
|
||||
_fieldDict[value2] = value;
|
||||
}
|
||||
}
|
||||
return new SymbolId(value2);
|
||||
}
|
||||
|
||||
public static SymbolId StringToCaseInsensitiveId(string value)
|
||||
{
|
||||
return StringToId(value).CaseInsensitiveIdentifier;
|
||||
}
|
||||
|
||||
public static SymbolId[] QualifiedStringToIds(string values)
|
||||
{
|
||||
if (values != null)
|
||||
{
|
||||
string[] array = values.Split('.');
|
||||
SymbolId[] array2 = new SymbolId[array.Length];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
ref SymbolId reference = ref array2[i];
|
||||
reference = StringToId(array[i]);
|
||||
}
|
||||
return array2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string IdToString(SymbolId id)
|
||||
{
|
||||
lock (_fieldDict)
|
||||
{
|
||||
if (id.IsCaseInsensitive)
|
||||
{
|
||||
return _fieldDict[id.Id | 0x1000000];
|
||||
}
|
||||
return _fieldDict[id.Id];
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ContainsId(SymbolId id)
|
||||
{
|
||||
lock (_fieldDict)
|
||||
{
|
||||
if (id.IsCaseInsensitive)
|
||||
{
|
||||
return _fieldDict.ContainsKey(id.Id | 0x1000000);
|
||||
}
|
||||
return _fieldDict.ContainsKey(id.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] IdsToStrings(IList<SymbolId> ids)
|
||||
{
|
||||
string[] array = new string[ids.Count];
|
||||
for (int i = 0; i < ids.Count; i++)
|
||||
{
|
||||
if (ids[i] == SymbolId.Empty)
|
||||
{
|
||||
array[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = IdToString(ids[i]);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static SymbolId[] StringsToIds(IList<string> values)
|
||||
{
|
||||
SymbolId[] array = new SymbolId[values.Count];
|
||||
for (int i = 0; i < values.Count; i++)
|
||||
{
|
||||
if (values[i] == null)
|
||||
{
|
||||
ref SymbolId reference = ref array[i];
|
||||
reference = SymbolId.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
ref SymbolId reference2 = ref array[i];
|
||||
reference2 = StringToId(values[i]);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static bool StringHasId(string symbol)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(symbol, "symbol");
|
||||
lock (_lockObj)
|
||||
{
|
||||
return _idDict.ContainsKey(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
public static SymbolId StringToIdOrEmpty(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return SymbolId.Empty;
|
||||
}
|
||||
return StringToId(value);
|
||||
}
|
||||
}
|
116
AspClassic.Scripting/SyntaxErrorException.cs
Normal file
116
AspClassic.Scripting/SyntaxErrorException.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
using AspClassic.Scripting.Utils;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public class SyntaxErrorException : Exception
|
||||
{
|
||||
private SourceSpan _span;
|
||||
|
||||
private string _sourceCode;
|
||||
|
||||
private string _sourceLine;
|
||||
|
||||
private string _sourcePath;
|
||||
|
||||
private Severity _severity;
|
||||
|
||||
private int _errorCode;
|
||||
|
||||
public SourceSpan RawSpan => _span;
|
||||
|
||||
public string SourceCode => _sourceCode;
|
||||
|
||||
public string SourcePath => _sourcePath;
|
||||
|
||||
public Severity Severity => _severity;
|
||||
|
||||
public int Line => _span.Start.Line;
|
||||
|
||||
public int Column => _span.Start.Column;
|
||||
|
||||
public int ErrorCode => _errorCode;
|
||||
|
||||
public SyntaxErrorException()
|
||||
{
|
||||
}
|
||||
|
||||
public SyntaxErrorException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public SyntaxErrorException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
||||
public SyntaxErrorException(string message, SourceUnit sourceUnit, SourceSpan span, int errorCode, Severity severity)
|
||||
: base(message)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(message, "message");
|
||||
_span = span;
|
||||
_severity = severity;
|
||||
_errorCode = errorCode;
|
||||
if (sourceUnit != null)
|
||||
{
|
||||
_sourcePath = sourceUnit.Path;
|
||||
try
|
||||
{
|
||||
_sourceCode = sourceUnit.GetCode();
|
||||
_sourceLine = sourceUnit.GetCodeLine(Line);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SyntaxErrorException(string message, string path, string code, string line, SourceSpan span, int errorCode, Severity severity)
|
||||
: base(message)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(message, "message");
|
||||
_span = span;
|
||||
_severity = severity;
|
||||
_errorCode = errorCode;
|
||||
_sourcePath = path;
|
||||
_sourceCode = code;
|
||||
_sourceLine = line;
|
||||
}
|
||||
|
||||
protected SyntaxErrorException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
_span = (SourceSpan)info.GetValue("Span", typeof(SourceSpan));
|
||||
_sourceCode = info.GetString("SourceCode");
|
||||
_sourcePath = info.GetString("SourcePath");
|
||||
_severity = (Severity)info.GetValue("Severity", typeof(Severity));
|
||||
_errorCode = info.GetInt32("ErrorCode");
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(info, "info");
|
||||
base.GetObjectData(info, context);
|
||||
info.AddValue("Span", _span);
|
||||
info.AddValue("SourceCode", _sourceCode);
|
||||
info.AddValue("SourcePath", _sourcePath);
|
||||
info.AddValue("Severity", _severity);
|
||||
info.AddValue("ErrorCode", _errorCode);
|
||||
}
|
||||
|
||||
public string GetSymbolDocumentName()
|
||||
{
|
||||
return _sourcePath;
|
||||
}
|
||||
|
||||
public string GetCodeLine()
|
||||
{
|
||||
return _sourceLine;
|
||||
}
|
||||
}
|
9
AspClassic.Scripting/TextContentProvider.cs
Normal file
9
AspClassic.Scripting/TextContentProvider.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public abstract class TextContentProvider
|
||||
{
|
||||
public abstract SourceCodeReader GetReader();
|
||||
}
|
23
AspClassic.Scripting/TokenCategory.cs
Normal file
23
AspClassic.Scripting/TokenCategory.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public enum TokenCategory
|
||||
{
|
||||
None = 0,
|
||||
EndOfStream = 1,
|
||||
WhiteSpace = 2,
|
||||
Comment = 3,
|
||||
LineComment = 4,
|
||||
DocComment = 5,
|
||||
NumericLiteral = 6,
|
||||
CharacterLiteral = 7,
|
||||
StringLiteral = 8,
|
||||
RegularExpressionLiteral = 9,
|
||||
Keyword = 10,
|
||||
Directive = 11,
|
||||
Operator = 12,
|
||||
Delimiter = 13,
|
||||
Identifier = 14,
|
||||
Grouping = 15,
|
||||
Error = 16,
|
||||
LanguageDefined = 256
|
||||
}
|
65
AspClassic.Scripting/TokenInfo.cs
Normal file
65
AspClassic.Scripting/TokenInfo.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Serializable]
|
||||
public struct TokenInfo : IEquatable<TokenInfo>
|
||||
{
|
||||
private TokenCategory _category;
|
||||
|
||||
private TokenTriggers _trigger;
|
||||
|
||||
private SourceSpan _span;
|
||||
|
||||
public TokenCategory Category
|
||||
{
|
||||
get
|
||||
{
|
||||
return _category;
|
||||
}
|
||||
set
|
||||
{
|
||||
_category = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TokenTriggers Trigger
|
||||
{
|
||||
get
|
||||
{
|
||||
return _trigger;
|
||||
}
|
||||
set
|
||||
{
|
||||
_trigger = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SourceSpan SourceSpan
|
||||
{
|
||||
get
|
||||
{
|
||||
return _span;
|
||||
}
|
||||
set
|
||||
{
|
||||
_span = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TokenInfo(SourceSpan span, TokenCategory category, TokenTriggers trigger)
|
||||
{
|
||||
_category = category;
|
||||
_trigger = trigger;
|
||||
_span = span;
|
||||
}
|
||||
|
||||
public bool Equals(TokenInfo other)
|
||||
{
|
||||
if (_category == other._category && _trigger == other._trigger)
|
||||
{
|
||||
return _span == other._span;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
103
AspClassic.Scripting/TokenKind.cs
Normal file
103
AspClassic.Scripting/TokenKind.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
namespace AspClassic.Scripting;
|
||||
|
||||
public enum TokenKind
|
||||
{
|
||||
Default,
|
||||
Error,
|
||||
Whitespace,
|
||||
EndOfLine,
|
||||
LineJoin,
|
||||
Indentation,
|
||||
SingleLineComment,
|
||||
MultiLineComment,
|
||||
NestableCommentStart,
|
||||
NestableCommentEnd,
|
||||
SingleLineDocComment,
|
||||
MultiLineDocComment,
|
||||
Directive,
|
||||
Keyword,
|
||||
Identifier,
|
||||
VerbatimIdentifier,
|
||||
Variable,
|
||||
IntegerLiteral,
|
||||
FloatLiteral,
|
||||
CharacterLiteral,
|
||||
String,
|
||||
UnicodeString,
|
||||
FormattedString,
|
||||
FormattedUnicodeString,
|
||||
LeftParenthesis,
|
||||
RightParenthesis,
|
||||
LeftBracket,
|
||||
RightBracket,
|
||||
LeftBrace,
|
||||
RightBrace,
|
||||
Comma,
|
||||
Dot,
|
||||
Semicolon,
|
||||
Colon,
|
||||
DoubleColon,
|
||||
TripleColon,
|
||||
Plus,
|
||||
PlusPlus,
|
||||
PlusEqual,
|
||||
Minus,
|
||||
MinusMinus,
|
||||
MinusEqual,
|
||||
Mul,
|
||||
MulEqual,
|
||||
Div,
|
||||
DivEqual,
|
||||
FloorDivide,
|
||||
FloorDivideEqual,
|
||||
Mod,
|
||||
ModEqual,
|
||||
Power,
|
||||
PowerEqual,
|
||||
LeftShift,
|
||||
LeftShiftEqual,
|
||||
RightShift,
|
||||
RightShiftEqual,
|
||||
BitwiseAnd,
|
||||
BitwiseAndEqual,
|
||||
BitwiseOr,
|
||||
BitwiseOrEqual,
|
||||
Xor,
|
||||
XorEqual,
|
||||
BooleanAnd,
|
||||
BooleanAndEqual,
|
||||
BooleanOr,
|
||||
BooleanOrEqual,
|
||||
Twiddle,
|
||||
TwiddleEqual,
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThanOrEqual,
|
||||
Assign,
|
||||
AssignAlias,
|
||||
AssignColon,
|
||||
Equal,
|
||||
StrictEqual,
|
||||
Not,
|
||||
NotEqual,
|
||||
StrictNotEqual,
|
||||
Unequal,
|
||||
CompareEqual,
|
||||
Match,
|
||||
NotMatch,
|
||||
Arrow,
|
||||
DoubleArrow,
|
||||
BackQuote,
|
||||
DoubleDot,
|
||||
TripleDot,
|
||||
At,
|
||||
DoubleAt,
|
||||
Question,
|
||||
DoubleQuestion,
|
||||
Backslash,
|
||||
DoubleBackslash,
|
||||
Dollar,
|
||||
DoubleDollar,
|
||||
LanguageDefined
|
||||
}
|
16
AspClassic.Scripting/TokenTriggers.cs
Normal file
16
AspClassic.Scripting/TokenTriggers.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace AspClassic.Scripting;
|
||||
|
||||
[Flags]
|
||||
public enum TokenTriggers
|
||||
{
|
||||
None = 0,
|
||||
MemberSelect = 1,
|
||||
MatchBraces = 2,
|
||||
ParameterStart = 0x10,
|
||||
ParameterNext = 0x20,
|
||||
ParameterEnd = 0x40,
|
||||
Parameter = 0x80,
|
||||
MethodTip = 0xF0
|
||||
}
|
348
AspClassic.Scripting/Utils/ArrayUtils.cs
Normal file
348
AspClassic.Scripting/Utils/ArrayUtils.cs
Normal file
|
@ -0,0 +1,348 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class ArrayUtils
|
||||
{
|
||||
internal sealed class FunctorComparer<T> : IComparer<T>
|
||||
{
|
||||
private readonly Comparison<T> _comparison;
|
||||
|
||||
public FunctorComparer(Comparison<T> comparison)
|
||||
{
|
||||
_comparison = comparison;
|
||||
}
|
||||
|
||||
public int Compare(T x, T y)
|
||||
{
|
||||
return _comparison(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly string[] EmptyStrings = new string[0];
|
||||
|
||||
public static readonly object[] EmptyObjects = new object[0];
|
||||
|
||||
public static IComparer<T> ToComparer<T>(Comparison<T> comparison)
|
||||
{
|
||||
return new FunctorComparer<T>(comparison);
|
||||
}
|
||||
|
||||
public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] input, Converter<TInput, TOutput> conv)
|
||||
{
|
||||
return Array.ConvertAll(input, conv);
|
||||
}
|
||||
|
||||
public static T[] FindAll<T>(T[] array, Predicate<T> match)
|
||||
{
|
||||
return Array.FindAll(array, match);
|
||||
}
|
||||
|
||||
public static void PrintTable(StringBuilder output, string[,] table)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(output, "output");
|
||||
ContractUtils.RequiresNotNull(table, "table");
|
||||
int num = 0;
|
||||
for (int i = 0; i < table.GetLength(0); i++)
|
||||
{
|
||||
if (table[i, 0].Length > num)
|
||||
{
|
||||
num = table[i, 0].Length;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < table.GetLength(0); j++)
|
||||
{
|
||||
output.Append(" ");
|
||||
output.Append(table[j, 0]);
|
||||
for (int k = table[j, 0].Length; k < num + 1; k++)
|
||||
{
|
||||
output.Append(' ');
|
||||
}
|
||||
output.AppendLine(table[j, 1]);
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] Copy<T>(T[] array)
|
||||
{
|
||||
if (array.Length <= 0)
|
||||
{
|
||||
return array;
|
||||
}
|
||||
return (T[])array.Clone();
|
||||
}
|
||||
|
||||
public static T[] MakeArray<T>(ICollection<T> list)
|
||||
{
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return new T[0];
|
||||
}
|
||||
T[] array = new T[list.Count];
|
||||
list.CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] MakeArray<T>(ICollection<T> elements, int reservedSlotsBefore, int reservedSlotsAfter)
|
||||
{
|
||||
if (reservedSlotsAfter < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("reservedSlotsAfter");
|
||||
}
|
||||
if (reservedSlotsBefore < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("reservedSlotsBefore");
|
||||
}
|
||||
if (elements == null)
|
||||
{
|
||||
return new T[reservedSlotsBefore + reservedSlotsAfter];
|
||||
}
|
||||
T[] array = new T[reservedSlotsBefore + elements.Count + reservedSlotsAfter];
|
||||
elements.CopyTo(array, reservedSlotsBefore);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] RotateRight<T>(T[] array, int count)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
if (count < 0 || count > array.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
T[] array2 = new T[array.Length];
|
||||
int num = array.Length - count;
|
||||
Array.Copy(array, 0, array2, count, num);
|
||||
Array.Copy(array, num, array2, 0, count);
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] ShiftRight<T>(T[] array, int count)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
T[] array2 = new T[array.Length + count];
|
||||
Array.Copy(array, 0, array2, count, array.Length);
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] ShiftLeft<T>(T[] array, int count)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
T[] array2 = new T[array.Length - count];
|
||||
Array.Copy(array, count, array2, 0, array2.Length);
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] Insert<T>(T item, IList<T> list)
|
||||
{
|
||||
T[] array = new T[list.Count + 1];
|
||||
array[0] = item;
|
||||
list.CopyTo(array, 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] Insert<T>(T item1, T item2, IList<T> list)
|
||||
{
|
||||
T[] array = new T[list.Count + 2];
|
||||
array[0] = item1;
|
||||
array[1] = item2;
|
||||
list.CopyTo(array, 2);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] Insert<T>(T item, T[] array)
|
||||
{
|
||||
T[] array2 = ShiftRight(array, 1);
|
||||
array2[0] = item;
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] Insert<T>(T item1, T item2, T[] array)
|
||||
{
|
||||
T[] array2 = ShiftRight(array, 2);
|
||||
array2[0] = item1;
|
||||
array2[1] = item2;
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] Append<T>(T[] array, T item)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
Array.Resize(ref array, array.Length + 1);
|
||||
array[array.Length - 1] = item;
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] AppendRange<T>(T[] array, IList<T> items)
|
||||
{
|
||||
return AppendRange(array, items, 0);
|
||||
}
|
||||
|
||||
public static T[] AppendRange<T>(T[] array, IList<T> items, int additionalItemCount)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
if (additionalItemCount < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("additionalItemCount");
|
||||
}
|
||||
int num = array.Length;
|
||||
Array.Resize(ref array, array.Length + items.Count + additionalItemCount);
|
||||
int num2 = 0;
|
||||
while (num2 < items.Count)
|
||||
{
|
||||
array[num] = items[num2];
|
||||
num2++;
|
||||
num++;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[,] Concatenate<T>(T[,] array1, T[,] array2)
|
||||
{
|
||||
int length = array1.GetLength(1);
|
||||
int length2 = array1.GetLength(0);
|
||||
int length3 = array2.GetLength(0);
|
||||
int num = length2 + length3;
|
||||
T[,] array3 = new T[num, length];
|
||||
for (int i = 0; i < length2; i++)
|
||||
{
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
array3[i, j] = array1[i, j];
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < length3; k++)
|
||||
{
|
||||
for (int l = 0; l < length; l++)
|
||||
{
|
||||
array3[k + length2, l] = array2[k, l];
|
||||
}
|
||||
}
|
||||
return array3;
|
||||
}
|
||||
|
||||
public static void SwapLastTwo<T>(T[] array)
|
||||
{
|
||||
T val = array[array.Length - 1];
|
||||
array[array.Length - 1] = array[array.Length - 2];
|
||||
array[array.Length - 2] = val;
|
||||
}
|
||||
|
||||
public static T[] RemoveFirst<T>(IList<T> list)
|
||||
{
|
||||
return ShiftLeft(MakeArray(list), 1);
|
||||
}
|
||||
|
||||
public static T[] RemoveFirst<T>(T[] array)
|
||||
{
|
||||
return ShiftLeft(array, 1);
|
||||
}
|
||||
|
||||
public static T[] RemoveLast<T>(T[] array)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
Array.Resize(ref array, array.Length - 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T[] RemoveAt<T>(IList<T> list, int indexToRemove)
|
||||
{
|
||||
return RemoveAt(MakeArray(list), indexToRemove);
|
||||
}
|
||||
|
||||
public static T[] RemoveAt<T>(T[] array, int indexToRemove)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
ContractUtils.Requires(indexToRemove >= 0 && indexToRemove < array.Length, "index");
|
||||
T[] array2 = new T[array.Length - 1];
|
||||
if (indexToRemove > 0)
|
||||
{
|
||||
Array.Copy(array, 0, array2, 0, indexToRemove);
|
||||
}
|
||||
int num = array.Length - indexToRemove - 1;
|
||||
if (num > 0)
|
||||
{
|
||||
Array.Copy(array, array.Length - num, array2, array2.Length - num, num);
|
||||
}
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] InsertAt<T>(IList<T> list, int index, params T[] items)
|
||||
{
|
||||
return InsertAt(MakeArray(list), index, items);
|
||||
}
|
||||
|
||||
public static T[] InsertAt<T>(T[] array, int index, params T[] items)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(array, "array");
|
||||
ContractUtils.RequiresNotNull(items, "items");
|
||||
ContractUtils.Requires(index >= 0 && index <= array.Length, "index");
|
||||
if (items.Length == 0)
|
||||
{
|
||||
return Copy(array);
|
||||
}
|
||||
T[] array2 = new T[array.Length + items.Length];
|
||||
if (index > 0)
|
||||
{
|
||||
Array.Copy(array, 0, array2, 0, index);
|
||||
}
|
||||
Array.Copy(items, 0, array2, index, items.Length);
|
||||
int num = array.Length - index;
|
||||
if (num > 0)
|
||||
{
|
||||
Array.Copy(array, array.Length - num, array2, array2.Length - num, num);
|
||||
}
|
||||
return array2;
|
||||
}
|
||||
|
||||
public static T[] ToArray<T>(ICollection<T> list)
|
||||
{
|
||||
if (!(list is T[] result))
|
||||
{
|
||||
T[] array = new T[list.Count];
|
||||
int num = 0;
|
||||
{
|
||||
foreach (T item in list)
|
||||
{
|
||||
array[num++] = item;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool ValueEquals<T>(this T[] array, T[] other)
|
||||
{
|
||||
if (other.Length != array.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
if (!object.Equals(array[i], other[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static T[] Reverse<T>(this T[] array)
|
||||
{
|
||||
T[] array2 = new T[array.Length];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array2[array.Length - i - 1] = array[i];
|
||||
}
|
||||
return array2;
|
||||
}
|
||||
}
|
100
AspClassic.Scripting/Utils/AssemblyQualifiedTypeName.cs
Normal file
100
AspClassic.Scripting/Utils/AssemblyQualifiedTypeName.cs
Normal file
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
[Serializable]
|
||||
internal struct AssemblyQualifiedTypeName : IEquatable<AssemblyQualifiedTypeName>
|
||||
{
|
||||
public readonly string TypeName;
|
||||
|
||||
public readonly AssemblyName AssemblyName;
|
||||
|
||||
public AssemblyQualifiedTypeName(string typeName, AssemblyName assemblyName)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(typeName, "typeName");
|
||||
ContractUtils.RequiresNotNull(assemblyName, "assemblyName");
|
||||
TypeName = typeName;
|
||||
AssemblyName = assemblyName;
|
||||
}
|
||||
|
||||
public AssemblyQualifiedTypeName(Type type)
|
||||
{
|
||||
TypeName = type.FullName;
|
||||
AssemblyName = type.Assembly.GetName();
|
||||
}
|
||||
|
||||
public AssemblyQualifiedTypeName(string assemblyQualifiedTypeName)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(assemblyQualifiedTypeName, "assemblyQualifiedTypeName");
|
||||
int num = assemblyQualifiedTypeName.IndexOf(",");
|
||||
if (num != -1)
|
||||
{
|
||||
TypeName = assemblyQualifiedTypeName.Substring(0, num).Trim();
|
||||
string text = assemblyQualifiedTypeName.Substring(num + 1).Trim();
|
||||
if (TypeName.Length > 0 && text.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
AssemblyName = new AssemblyName(text);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException($"Invalid assembly qualified name '{assemblyQualifiedTypeName}': {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"Invalid assembly qualified name '{assemblyQualifiedTypeName}'");
|
||||
}
|
||||
|
||||
internal static AssemblyQualifiedTypeName ParseArgument(string str, string argumentName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new AssemblyQualifiedTypeName(str);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
throw new ArgumentException(ex.Message, argumentName, ex.InnerException);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(AssemblyQualifiedTypeName other)
|
||||
{
|
||||
if (TypeName == other.TypeName)
|
||||
{
|
||||
return AssemblyName.FullName == other.AssemblyName.FullName;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is AssemblyQualifiedTypeName)
|
||||
{
|
||||
return Equals((AssemblyQualifiedTypeName)obj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return TypeName.GetHashCode() ^ AssemblyName.FullName.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return TypeName + ", " + AssemblyName.FullName;
|
||||
}
|
||||
|
||||
public static bool operator ==(AssemblyQualifiedTypeName name, AssemblyQualifiedTypeName other)
|
||||
{
|
||||
return name.Equals(other);
|
||||
}
|
||||
|
||||
public static bool operator !=(AssemblyQualifiedTypeName name, AssemblyQualifiedTypeName other)
|
||||
{
|
||||
return !name.Equals(other);
|
||||
}
|
||||
}
|
42
AspClassic.Scripting/Utils/Assert.cs
Normal file
42
AspClassic.Scripting/Utils/Assert.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
#define DEBUG
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class Assert
|
||||
{
|
||||
[Conditional("DEBUG")]
|
||||
public static void NotNull(object var)
|
||||
{
|
||||
Debug.Assert(var != null);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void NotNull(object var1, object var2)
|
||||
{
|
||||
Debug.Assert(var1 != null && var2 != null);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void NotNull(object var1, object var2, object var3)
|
||||
{
|
||||
Debug.Assert(var1 != null && var2 != null && var3 != null);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void NotNullItems<T>(IEnumerable<T> items) where T : class
|
||||
{
|
||||
Debug.Assert(items != null);
|
||||
foreach (T item in items)
|
||||
{
|
||||
Debug.Assert(item != null);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void NotEmpty(string str)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(str));
|
||||
}
|
||||
}
|
97
AspClassic.Scripting/Utils/CheckedDictionaryEnumerator.cs
Normal file
97
AspClassic.Scripting/Utils/CheckedDictionaryEnumerator.cs
Normal file
|
@ -0,0 +1,97 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal abstract class CheckedDictionaryEnumerator : IDictionaryEnumerator, IEnumerator<KeyValuePair<object, object>>, IDisposable, IEnumerator
|
||||
{
|
||||
private enum EnumeratorState
|
||||
{
|
||||
NotStarted,
|
||||
Started,
|
||||
Ended
|
||||
}
|
||||
|
||||
private EnumeratorState _enumeratorState;
|
||||
|
||||
public DictionaryEntry Entry
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckEnumeratorState();
|
||||
return new DictionaryEntry(Key, Value);
|
||||
}
|
||||
}
|
||||
|
||||
public object Key
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckEnumeratorState();
|
||||
return GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckEnumeratorState();
|
||||
return GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
public object Current => Entry;
|
||||
|
||||
KeyValuePair<object, object> IEnumerator<KeyValuePair<object, object>>.Current => new KeyValuePair<object, object>(Key, Value);
|
||||
|
||||
private void CheckEnumeratorState()
|
||||
{
|
||||
if (_enumeratorState == EnumeratorState.NotStarted)
|
||||
{
|
||||
throw Error.EnumerationNotStarted();
|
||||
}
|
||||
if (_enumeratorState == EnumeratorState.Ended)
|
||||
{
|
||||
throw Error.EnumerationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_enumeratorState == EnumeratorState.Ended)
|
||||
{
|
||||
throw Error.EnumerationFinished();
|
||||
}
|
||||
bool flag = DoMoveNext();
|
||||
if (flag)
|
||||
{
|
||||
_enumeratorState = EnumeratorState.Started;
|
||||
}
|
||||
else
|
||||
{
|
||||
_enumeratorState = EnumeratorState.Ended;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
DoReset();
|
||||
_enumeratorState = EnumeratorState.NotStarted;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected abstract object GetKey();
|
||||
|
||||
protected abstract object GetValue();
|
||||
|
||||
protected abstract bool DoMoveNext();
|
||||
|
||||
protected abstract void DoReset();
|
||||
}
|
92
AspClassic.Scripting/Utils/CollectionExtensions.cs
Normal file
92
AspClassic.Scripting/Utils/CollectionExtensions.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class CollectionExtensions
|
||||
{
|
||||
internal static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
if (enumerable == null)
|
||||
{
|
||||
return EmptyReadOnlyCollection<T>.Instance;
|
||||
}
|
||||
if (enumerable is ReadOnlyCollection<T> result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if (enumerable is ICollection<T> collection)
|
||||
{
|
||||
int count = collection.Count;
|
||||
if (count == 0)
|
||||
{
|
||||
return EmptyReadOnlyCollection<T>.Instance;
|
||||
}
|
||||
T[] array = new T[count];
|
||||
collection.CopyTo(array, 0);
|
||||
return new ReadOnlyCollection<T>(array);
|
||||
}
|
||||
return new ReadOnlyCollection<T>(new List<T>(enumerable).ToArray());
|
||||
}
|
||||
|
||||
internal static T[] ToArray<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
if (enumerable is ICollection<T> collection)
|
||||
{
|
||||
T[] array = new T[collection.Count];
|
||||
collection.CopyTo(array, 0);
|
||||
return array;
|
||||
}
|
||||
return new List<T>(enumerable).ToArray();
|
||||
}
|
||||
|
||||
internal static bool Any<T>(this IEnumerable<T> source, Func<T, bool> predicate)
|
||||
{
|
||||
foreach (T item in source)
|
||||
{
|
||||
if (predicate(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
|
||||
{
|
||||
using IEnumerator<TSource> enumerator = source.GetEnumerator();
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
throw new ArgumentException("Collection is empty", "source");
|
||||
}
|
||||
TSource val = enumerator.Current;
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
val = func(val, enumerator.Current);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
internal static T[] AddFirst<T>(this IList<T> list, T item)
|
||||
{
|
||||
T[] array = new T[list.Count + 1];
|
||||
array[0] = item;
|
||||
list.CopyTo(array, 1);
|
||||
return array;
|
||||
}
|
||||
|
||||
internal static bool TrueForAll<T>(this IEnumerable<T> collection, Predicate<T> predicate)
|
||||
{
|
||||
ContractUtils.RequiresNotNull(collection, "collection");
|
||||
ContractUtils.RequiresNotNull(predicate, "predicate");
|
||||
foreach (T item in collection)
|
||||
{
|
||||
if (!predicate(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
107
AspClassic.Scripting/Utils/ConsoleInputStream.cs
Normal file
107
AspClassic.Scripting/Utils/ConsoleInputStream.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
public sealed class ConsoleInputStream : Stream
|
||||
{
|
||||
private const int MinimalBufferSize = 4096;
|
||||
|
||||
public static readonly ConsoleInputStream Instance = new ConsoleInputStream();
|
||||
|
||||
private readonly Stream _input;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
private readonly byte[] _buffer = new byte[4096];
|
||||
|
||||
private int _bufferPos;
|
||||
|
||||
private int _bufferSize;
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private ConsoleInputStream()
|
||||
{
|
||||
_input = Console.OpenStandardInput();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
int num;
|
||||
if (_bufferSize > 0)
|
||||
{
|
||||
num = Math.Min(count, _bufferSize);
|
||||
Buffer.BlockCopy(_buffer, _bufferPos, buffer, offset, num);
|
||||
_bufferPos += num;
|
||||
_bufferSize -= num;
|
||||
offset += num;
|
||||
count -= num;
|
||||
}
|
||||
else
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
if (count > 0)
|
||||
{
|
||||
if (count < 4096)
|
||||
{
|
||||
int num2 = _input.Read(_buffer, 0, 4096);
|
||||
int num3 = Math.Min(num2, count);
|
||||
Buffer.BlockCopy(_buffer, 0, buffer, offset, num3);
|
||||
_bufferSize = num2 - num3;
|
||||
_bufferPos = num3;
|
||||
return num + num3;
|
||||
}
|
||||
return num + _input.Read(buffer, offset, count);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
8
AspClassic.Scripting/Utils/ConsoleStreamType.cs
Normal file
8
AspClassic.Scripting/Utils/ConsoleStreamType.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
public enum ConsoleStreamType
|
||||
{
|
||||
Input,
|
||||
Output,
|
||||
ErrorOutput
|
||||
}
|
113
AspClassic.Scripting/Utils/ContractUtils.cs
Normal file
113
AspClassic.Scripting/Utils/ContractUtils.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class ContractUtils
|
||||
{
|
||||
public static void RequiresNotNull(object value, string paramName)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Requires(bool precondition)
|
||||
{
|
||||
if (!precondition)
|
||||
{
|
||||
throw new ArgumentException(Strings.MethodPreconditionViolated);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Requires(bool precondition, string paramName)
|
||||
{
|
||||
if (!precondition)
|
||||
{
|
||||
throw new ArgumentException(Strings.InvalidArgumentValue, paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Requires(bool precondition, string paramName, string message)
|
||||
{
|
||||
if (!precondition)
|
||||
{
|
||||
throw new ArgumentException(message, paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresNotEmpty(string str, string paramName)
|
||||
{
|
||||
RequiresNotNull(str, paramName);
|
||||
if (str.Length == 0)
|
||||
{
|
||||
throw new ArgumentException(Strings.NonEmptyStringRequired, paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresNotEmpty<T>(ICollection<T> collection, string paramName)
|
||||
{
|
||||
RequiresNotNull(collection, paramName);
|
||||
if (collection.Count == 0)
|
||||
{
|
||||
throw new ArgumentException(Strings.NonEmptyCollectionRequired, paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresArrayRange<T>(IList<T> array, int offset, int count, string offsetName, string countName)
|
||||
{
|
||||
RequiresArrayRange(array.Count, offset, count, offsetName, countName);
|
||||
}
|
||||
|
||||
public static void RequiresArrayRange(int arraySize, int offset, int count, string offsetName, string countName)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(countName);
|
||||
}
|
||||
if (offset < 0 || arraySize - offset < count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(offsetName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresNotNullItems<T>(IList<T> array, string arrayName)
|
||||
{
|
||||
RequiresNotNull(array, arrayName);
|
||||
for (int i = 0; i < array.Count; i++)
|
||||
{
|
||||
if (array[i] == null)
|
||||
{
|
||||
throw ExceptionUtils.MakeArgumentItemNullException(i, arrayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresNotNullItems<T>(IEnumerable<T> collection, string collectionName)
|
||||
{
|
||||
RequiresNotNull(collection, collectionName);
|
||||
int num = 0;
|
||||
foreach (T item in collection)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw ExceptionUtils.MakeArgumentItemNullException(num, collectionName);
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RequiresListRange(IList array, int offset, int count, string offsetName, string countName)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(countName);
|
||||
}
|
||||
if (offset < 0 || array.Count - offset < count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(offsetName);
|
||||
}
|
||||
}
|
||||
}
|
49
AspClassic.Scripting/Utils/DictionaryUnionEnumerator.cs
Normal file
49
AspClassic.Scripting/Utils/DictionaryUnionEnumerator.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal class DictionaryUnionEnumerator : CheckedDictionaryEnumerator
|
||||
{
|
||||
private IList<IDictionaryEnumerator> _enums;
|
||||
|
||||
private int _current;
|
||||
|
||||
public DictionaryUnionEnumerator(IList<IDictionaryEnumerator> enums)
|
||||
{
|
||||
_enums = enums;
|
||||
}
|
||||
|
||||
protected override object GetKey()
|
||||
{
|
||||
return _enums[_current].Key;
|
||||
}
|
||||
|
||||
protected override object GetValue()
|
||||
{
|
||||
return _enums[_current].Value;
|
||||
}
|
||||
|
||||
protected override bool DoMoveNext()
|
||||
{
|
||||
if (_current == _enums.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_enums[_current].MoveNext())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_current++;
|
||||
return DoMoveNext();
|
||||
}
|
||||
|
||||
protected override void DoReset()
|
||||
{
|
||||
for (int i = 0; i < _enums.Count; i++)
|
||||
{
|
||||
_enums[i].Reset();
|
||||
}
|
||||
_current = 0;
|
||||
}
|
||||
}
|
6
AspClassic.Scripting/Utils/EmptyArray.cs
Normal file
6
AspClassic.Scripting/Utils/EmptyArray.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class EmptyArray<T>
|
||||
{
|
||||
internal static T[] Instance = new T[0];
|
||||
}
|
8
AspClassic.Scripting/Utils/EmptyReadOnlyCollection.cs
Normal file
8
AspClassic.Scripting/Utils/EmptyReadOnlyCollection.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
internal static class EmptyReadOnlyCollection<T>
|
||||
{
|
||||
internal static ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new T[0]);
|
||||
}
|
13
AspClassic.Scripting/Utils/EnumBounds.cs
Normal file
13
AspClassic.Scripting/Utils/EnumBounds.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace AspClassic.Scripting.Utils;
|
||||
|
||||
public static class EnumBounds
|
||||
{
|
||||
public static bool IsValid(this SourceCodeKind value)
|
||||
{
|
||||
if (value > SourceCodeKind.Unspecified)
|
||||
{
|
||||
return value <= SourceCodeKind.AutoDetect;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue