198 lines
6.6 KiB
C#
198 lines
6.6 KiB
C#
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);
|
|
}
|
|
}
|