From 6533e9c02e46207833f872733228a73c9c1d33ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20L=2E=20Charlier?= Date: Fri, 29 Dec 2023 17:05:30 +0100 Subject: [PATCH] feat: introduce the interface IContext and variables as Func (#231) feat: introduce the interface IContext --- Expressif/Context.cs | 8 +++++- Expressif/Expression.cs | 4 +-- Expressif/ExpressionBuilder.cs | 4 +-- Expressif/Functions/BaseExpressionFactory.cs | 14 +++++----- Expressif/Functions/ExpressionFactory.cs | 6 ++--- Expressif/Functions/ExpressionMember.cs | 27 -------------------- Expressif/Predicates/PredicationFactory.cs | 10 ++++---- Expressif/Predication.cs | 4 +-- Expressif/PredicationBuilder.cs | 4 +-- Expressif/Values/ContextVariables.cs | 18 ++++++++----- 10 files changed, 42 insertions(+), 57 deletions(-) delete mode 100644 Expressif/Functions/ExpressionMember.cs diff --git a/Expressif/Context.cs b/Expressif/Context.cs index e545922..cc848c3 100644 --- a/Expressif/Context.cs +++ b/Expressif/Context.cs @@ -7,8 +7,14 @@ namespace Expressif; -public class Context +public class Context : IContext { public ContextVariables Variables { get; } = new (); public ContextObject CurrentObject { get; } = new (); } + +public interface IContext +{ + ContextVariables Variables { get; } + ContextObject CurrentObject { get; } +} diff --git a/Expressif/Expression.cs b/Expressif/Expression.cs index 71c8e28..a6ff818 100644 --- a/Expressif/Expression.cs +++ b/Expressif/Expression.cs @@ -12,9 +12,9 @@ public class Expression : IFunction private readonly IFunction expression; public Expression(string code) : this(code, new Context()) { } - public Expression(string code, Context context) + public Expression(string code, IContext context) : this(code, context, new ExpressionFactory()) { } - public Expression(string code, Context context, ExpressionFactory factory) + public Expression(string code, IContext context, ExpressionFactory factory) => expression = factory.Instantiate(code, context); public object? Evaluate(object? value) => expression.Evaluate(value); diff --git a/Expressif/ExpressionBuilder.cs b/Expressif/ExpressionBuilder.cs index ce72a1d..cc96eef 100644 --- a/Expressif/ExpressionBuilder.cs +++ b/Expressif/ExpressionBuilder.cs @@ -15,13 +15,13 @@ namespace Expressif; public class ExpressionBuilder { - private Context Context { get; } + private IContext Context { get; } private ExpressionFactory Factory { get; } private ExpressionSerializer Serializer { get; } public ExpressionBuilder() : this(new Context()) { } - public ExpressionBuilder(Context? context = null, ExpressionFactory? factory = null, ExpressionSerializer? serializer = null) + public ExpressionBuilder(IContext? context = null, ExpressionFactory? factory = null, ExpressionSerializer? serializer = null) => (Context, Factory, Serializer) = (context ?? new Context(), factory ?? new ExpressionFactory(), serializer ?? new ExpressionSerializer()); private Queue Pile { get; } = new(); diff --git a/Expressif/Functions/BaseExpressionFactory.cs b/Expressif/Functions/BaseExpressionFactory.cs index 36051f3..40f99f9 100644 --- a/Expressif/Functions/BaseExpressionFactory.cs +++ b/Expressif/Functions/BaseExpressionFactory.cs @@ -18,10 +18,10 @@ public abstract class BaseExpressionFactory protected BaseExpressionFactory(BaseTypeMapper typeSetter) => TypeMapper = typeSetter; - protected internal T Instantiate(string functionName, IParameter[] parameters, Context context) + protected internal T Instantiate(string functionName, IParameter[] parameters, IContext context) => Instantiate(TypeMapper.Execute(functionName), parameters, context); - protected T Instantiate(Type type, IParameter[] parameters, Context context) + protected T Instantiate(Type type, IParameter[] parameters, IContext context) { var ctor = GetMatchingConstructor(type, parameters.Length); @@ -53,9 +53,9 @@ protected internal ConstructorInfo GetMatchingConstructor(Type type, int paramCo => type.GetConstructors().SingleOrDefault(x => x.GetParameters().Length == paramCount) ?? throw new MissingOrUnexpectedParametersFunctionException(type.Name, paramCount); - protected Delegate InstantiateScalarDelegate(IParameter parameter, Type scalarType, Context context) + protected Delegate InstantiateScalarDelegate(IParameter parameter, Type scalarType, IContext context) { - var instantiate = typeof(BaseExpressionFactory).GetMethod(nameof(InstantiateScalarResolver), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IParameter), typeof(Context)]) + var instantiate = typeof(BaseExpressionFactory).GetMethod(nameof(InstantiateScalarResolver), BindingFlags.Static | BindingFlags.NonPublic, [typeof(IParameter), typeof(IContext)]) ?? throw new InvalidProgramException(nameof(InstantiateScalarResolver)); var instantiateGeneric = instantiate.MakeGenericMethod(scalarType); var resolver = instantiateGeneric.Invoke(null, new object[] { parameter, context })!; @@ -66,7 +66,7 @@ protected Delegate InstantiateScalarDelegate(IParameter parameter, Type scalarTy return Delegate.CreateDelegate(funcType, resolver, execute); } - private static IScalarResolver InstantiateScalarResolver(IParameter parameter, Context context) + private static IScalarResolver InstantiateScalarResolver(IParameter parameter, IContext context) => parameter switch { LiteralParameter l => InstantiateScalarResolver(typeof(LiteralScalarResolver), [l.Value]), @@ -79,7 +79,7 @@ private static IScalarResolver InstantiateScalarResolver(IParameter parame private static IScalarResolver InstantiateScalarResolver(Type generic, object[] parameters) => (Activator.CreateInstance(generic, parameters) as IScalarResolver)!; - protected Delegate InstantiateIntervalDelegate(IParameter parameter, Type type, Context context) + protected Delegate InstantiateIntervalDelegate(IParameter parameter, Type type, IContext context) { if (parameter is not IntervalParameter i) throw new ArgumentOutOfRangeException(nameof(parameter)); @@ -99,7 +99,7 @@ protected Delegate InstantiateIntervalDelegate(IParameter parameter, Type type, return Delegate.CreateDelegate(funcType, resolver, execute); } - protected Delegate InstantiateInputExpressionDelegate(InputExpressionParameter exp, Type type, Context context) + protected Delegate InstantiateInputExpressionDelegate(InputExpressionParameter exp, Type type, IContext context) { var functions = new List(); foreach (var member in exp.Expression.Members) diff --git a/Expressif/Functions/ExpressionFactory.cs b/Expressif/Functions/ExpressionFactory.cs index e1922a5..09f3841 100644 --- a/Expressif/Functions/ExpressionFactory.cs +++ b/Expressif/Functions/ExpressionFactory.cs @@ -20,7 +20,7 @@ public class ExpressionFactory : BaseExpressionFactory public ExpressionFactory() : base(new FunctionTypeMapper()) { } - public IFunction Instantiate(string code, Context context) + public IFunction Instantiate(string code, IContext context) { var expression = Parser.Parse(code); @@ -30,9 +30,9 @@ public IFunction Instantiate(string code, Context context) return new ChainFunction(functions); } - public IFunction Instantiate(string name, IParameter[] parameters, Context context) + public IFunction Instantiate(string name, IParameter[] parameters, IContext context) => Instantiate(name, parameters, context); - public IFunction Instantiate(Type type, IParameter[] parameters, Context context) + public IFunction Instantiate(Type type, IParameter[] parameters, IContext context) => Instantiate(type, parameters, context); } diff --git a/Expressif/Functions/ExpressionMember.cs b/Expressif/Functions/ExpressionMember.cs deleted file mode 100644 index 657be82..0000000 --- a/Expressif/Functions/ExpressionMember.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Expressif.Parsers; -using Expressif.Values; -using Expressif.Values.Special; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Expressif.Functions; - -public record class ExpressionMember(Type Type, object?[] Parameters) -{ - public IFunction Build(Context context, ExpressionFactory factory) - { - var typedParameters = new List(); - foreach (var parameter in Parameters) - { - typedParameters.Add(parameter switch - { - IParameter p => p, - _ => new LiteralParameter(parameter?.ToString() ?? new Null().Keyword) - }); - } - return factory.Instantiate(Type, typedParameters.ToArray(), context); - } -} diff --git a/Expressif/Predicates/PredicationFactory.cs b/Expressif/Predicates/PredicationFactory.cs index dad055e..020ddce 100644 --- a/Expressif/Predicates/PredicationFactory.cs +++ b/Expressif/Predicates/PredicationFactory.cs @@ -26,14 +26,14 @@ protected internal PredicationFactory(PredicateTypeMapper mapper, UnaryOperatorF public PredicationFactory() : this(new PredicateTypeMapper(), new UnaryOperatorFactory(), new BinaryOperatorFactory()) { } - public virtual IPredicate Instantiate(string code, Context context) + public virtual IPredicate Instantiate(string code, IContext context) { var predication = Parser.Parse(code); var predicate = Instantiate(predication, context); return predicate; } - public IPredicate Instantiate(IPredication predication, Context context) + public IPredicate Instantiate(IPredication predication, IContext context) => predication switch { SinglePredication single => Instantiate(single, context), @@ -42,7 +42,7 @@ public IPredicate Instantiate(IPredication predication, Context context) _ => throw new NotImplementedException() }; - internal IPredicate Instantiate(SinglePredication basic, Context context) + internal IPredicate Instantiate(SinglePredication basic, IContext context) { var predicates = new List(); foreach (var predicate in basic.Members) @@ -50,13 +50,13 @@ internal IPredicate Instantiate(SinglePredication basic, Context context) return predicates[0]; } - internal IPredicate Instantiate(UnaryPredication unary, Context context) + internal IPredicate Instantiate(UnaryPredication unary, IContext context) { var predicate = Instantiate(unary.Member, context); return UnaryOperatorFactory.Instantiate(unary.Operator.Name, predicate); } - internal IPredicate Instantiate(BinaryPredication binary, Context context) + internal IPredicate Instantiate(BinaryPredication binary, IContext context) { var left = Instantiate(binary.LeftMember, context); var right = Instantiate(binary.RightMember, context); diff --git a/Expressif/Predication.cs b/Expressif/Predication.cs index aef8339..7775af0 100644 --- a/Expressif/Predication.cs +++ b/Expressif/Predication.cs @@ -14,9 +14,9 @@ public class Predication : IPredicate public Predication(string code) : this(code, new Context()) { } - public Predication(string code, Context context) + public Predication(string code, IContext context) : this(code, context, new PredicationFactory()) { } - public Predication(string code, Context context, PredicationFactory factory) + public Predication(string code, IContext context, PredicationFactory factory) => predicate = factory.Instantiate(code, context); public virtual bool Evaluate(object? value) => predicate.Evaluate(value)!; diff --git a/Expressif/PredicationBuilder.cs b/Expressif/PredicationBuilder.cs index ac017ae..7545bc4 100644 --- a/Expressif/PredicationBuilder.cs +++ b/Expressif/PredicationBuilder.cs @@ -13,13 +13,13 @@ namespace Expressif; public class PredicationBuilder { - private Context Context { get; } + private IContext Context { get; } private PredicationFactory Factory { get; } private PredicationSerializer Serializer { get; } public PredicationBuilder() : this(new Context()) { } - public PredicationBuilder(Context? context = null, PredicationFactory? factory = null, PredicationSerializer? serializer = null) + public PredicationBuilder(IContext? context = null, PredicationFactory? factory = null, PredicationSerializer? serializer = null) => (Context, Factory, Serializer) = (context ?? new Context(), factory ?? new(), serializer ?? new()); private IPredication? Pile { get; set; } diff --git a/Expressif/Values/ContextVariables.cs b/Expressif/Values/ContextVariables.cs index 41d8a32..1d08bc0 100644 --- a/Expressif/Values/ContextVariables.cs +++ b/Expressif/Values/ContextVariables.cs @@ -9,9 +9,9 @@ namespace Expressif.Values; public class ContextVariables { - private IDictionary Variables { get; } = new Dictionary(); + private IDictionary> Variables { get; } = new Dictionary>(); - internal void Add(string name, IScalarResolver value) + public void Add(string name, Func value) { name = name.StartsWith('@') ? name[1..] : name; if (Variables.ContainsKey(name)) @@ -20,9 +20,12 @@ internal void Add(string name, IScalarResolver value) } public void Add(string name, object value) - => Add(name, new LiteralScalarResolver(value)); + { + var resolver = new LiteralScalarResolver(value); + Add(name, () => resolver.Execute()); + } - internal void Set(string name, IScalarResolver value) + public void Set(string name, Func value) { name = name.StartsWith('@') ? name[1..] : name; if (Variables.ContainsKey(name)) @@ -32,7 +35,10 @@ internal void Set(string name, IScalarResolver value) } public void Set(string name, object value) - => Set(name, new LiteralScalarResolver(value)); + { + var resolver = new LiteralScalarResolver(value); + Set(name, () => resolver.Execute()); + } public void Remove(string name) { @@ -49,7 +55,7 @@ public object? this[string name] { name = name.StartsWith('@') ? name[1..] : name; if (Variables.TryGetValue(name, out var value)) - return value.Execute(); + return value.Invoke(); throw new UnexpectedVariableException(name); } }