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

203 lines
6.7 KiB
C#

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;
}
}