182 lines
5.4 KiB
C#
182 lines
5.4 KiB
C#
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);
|
|
}
|
|
}
|