Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ var expression = new Expression("1+2");
var result = expression.Evaluate();
```

## Another usage Example ( Inject your expression object where you want and evaluate formulas supplying them as argument of the "Evaluate" method )
```c
var expression = new Expression();
var result = expression.Evaluate("1+2");
```

For further detail of usage please see the ([Usage wiki page](https://github.com/bijington/expressive/wiki/Usage))

## Playground
Expand Down
94 changes: 20 additions & 74 deletions Source/Expressive/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,87 +140,33 @@ public Context(ExpressiveOptions options, CultureInfo mainCurrentCulture, Cultur
#endregion

#region Functions
// Conversion
this.RegisterFunction(new DateFunction());
this.RegisterFunction(new DecimalFunction());
this.RegisterFunction(new DoubleFunction());
this.RegisterFunction(new IntegerFunction());
this.RegisterFunction(new LongFunction());
this.RegisterFunction(new StringFunction());
// Date
this.RegisterFunction(new AddDaysFunction());
this.RegisterFunction(new AddHoursFunction());
this.RegisterFunction(new AddMillisecondsFunction());
this.RegisterFunction(new AddMinutesFunction());
this.RegisterFunction(new AddMonthsFunction());
this.RegisterFunction(new AddSecondsFunction());
this.RegisterFunction(new AddYearsFunction());
this.RegisterFunction(new DayOfFunction());
this.RegisterFunction(new DaysBetweenFunction());
this.RegisterFunction(new HourOfFunction());
this.RegisterFunction(new HoursBetweenFunction());
this.RegisterFunction(new MillisecondOfFunction());
this.RegisterFunction(new MillisecondsBetweenFunction());
this.RegisterFunction(new MinuteOfFunction());
this.RegisterFunction(new MinutesBetweenFunction());
this.RegisterFunction(new MonthOfFunction());
this.RegisterFunction(new SecondOfFunction());
this.RegisterFunction(new SecondsBetweenFunction());
this.RegisterFunction(new YearOfFunction());
// Mathematical
this.RegisterFunction(new AbsFunction());
this.RegisterFunction(new AcosFunction());
this.RegisterFunction(new AsinFunction());
this.RegisterFunction(new AtanFunction());
this.RegisterFunction(new CeilingFunction());
this.RegisterFunction(new CosFunction());
this.RegisterFunction(new CountFunction());
this.RegisterFunction(new ExpFunction());
this.RegisterFunction(new FloorFunction());
this.RegisterFunction(new IEEERemainderFunction());
this.RegisterFunction(new Log10Function());
this.RegisterFunction(new LogFunction());
this.RegisterFunction(new PowFunction());
this.RegisterFunction(new RandomFunction());
this.RegisterFunction(new RoundFunction());
this.RegisterFunction(new SignFunction());
this.RegisterFunction(new SinFunction());
this.RegisterFunction(new SqrtFunction());
this.RegisterFunction(new SumFunction());
this.RegisterFunction(new TanFunction());
this.RegisterFunction(new TruncateFunction());
// Mathematical Constants
this.RegisterFunction(new EFunction());
this.RegisterFunction(new PIFunction());
// Logical
this.RegisterFunction(new IfFunction());
this.RegisterFunction(new InFunction());
// Relational
this.RegisterFunction(new MaxFunction());
this.RegisterFunction(new MinFunction());
// Statistical
this.RegisterFunction(new AverageFunction());
this.RegisterFunction(new MeanFunction());
this.RegisterFunction(new MedianFunction());
this.RegisterFunction(new ModeFunction());
// String
this.RegisterFunction(new ContainsFunction());
this.RegisterFunction(new EndsWithFunction());
this.RegisterFunction(new LengthFunction());
this.RegisterFunction(new PadLeftFunction());
this.RegisterFunction(new PadRightFunction());
this.RegisterFunction(new RegexFunction());
this.RegisterFunction(new StartsWithFunction());
this.RegisterFunction(new SubstringFunction());
this.RegisterFunction(new ConcatFunction());
this.RegisterFunction(new IndexOfFunction());
// Getting all types implementing "IFunction" interface
var functionTypeInfos = Utils.Reflective.GetClassesImplementingInterface(typeof(IFunction));
// Getting our instances from types
var functions = Utils.Reflective.GetInstances<IFunction>(functionTypeInfos).Select(element => (IFunction)element).ToList();
// Register our functions
this.RegisterFunctions(functions);
#endregion
}

#endregion

#region Public Methods

/// <summary>
/// Registers the supplied <paramref name="functions"/> for use within compiling and evaluating an <see cref="Expression"/>.
/// </summary>
/// <param name="functions">The list of <see cref="IFunction"/> to perform the function evaluation.</param>
/// <param name="force">Whether to forcefully override any existing function.</param>
public void RegisterFunctions(List<IFunction> functions, bool force = false)
{
if (functions is null)
{
throw new ArgumentNullException(nameof(functions));
}
functions.ForEach(function => RegisterFunction(function, force));
}

/// <summary>
/// Registers the supplied <paramref name="function"/> for use within compiling and evaluating an <see cref="Expression"/>.
/// </summary>
Expand Down
72 changes: 69 additions & 3 deletions Source/Expressive/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public sealed class Expression : IExpression

private IExpression compiledExpression;
private readonly Context context;
private readonly string originalExpression;
private string originalExpression;
private readonly ExpressionParser parser;
private string[] referencedVariables;

Expand Down Expand Up @@ -68,7 +68,7 @@ public IReadOnlyCollection<string> ReferencedVariables
/// </summary>
/// <param name="expression">The expression to be evaluated.</param>
/// <param name="options">The <see cref="ExpressiveOptions"/> to use when evaluating.</param>
public Expression(string expression, ExpressiveOptions options = ExpressiveOptions.None) : this(expression, new Context(options))
public Expression(string expression = "", ExpressiveOptions options = ExpressiveOptions.None) : this(expression, new Context(options))
{
}

Expand Down Expand Up @@ -108,6 +108,18 @@ public object Evaluate(IDictionary<string, object> variables = null)
}
}

/// <summary>
/// Evaluates the supplied <paramref name="expression"/> using the supplied <paramref name="variables"/> and returns the result.
/// </summary>
/// <param name="expression">The expression to be evaluated.</param>
/// <param name="variables">The variables to be used in the evaluation.</param>
/// <returns>The result of the evaluation.</returns>
public object Evaluate(string expression, IDictionary<string, object> variables = null)
{
this.originalExpression = expression;
return Evaluate(variables);
}

/// <summary>
/// Evaluates the expression using the supplied <paramref name="variables"/> and returns the result.
/// </summary>
Expand All @@ -130,6 +142,19 @@ public T Evaluate<T>(IDictionary<string, object> variables = null)
}
}

/// <summary>
/// Evaluates the supplied <paramref name="expression"/> using the supplied <paramref name="variables"/> and returns the result.
/// </summary>
/// <exception cref="Exceptions.ExpressiveException">Thrown when there is a break in the evaluation process, check the InnerException for further information.</exception>
/// <param name="variables">The variables to be used in the evaluation.</param>
/// <param name="expression">The expression to be evaluated.</param>
/// <returns>The result of the evaluation.</returns>
public T Evaluate<T>(string expression, IDictionary<string, object> variables = null)
{
this.originalExpression = expression;
return Evaluate<T>(variables);
}

/// <summary>
/// Evaluates the expression using the supplied <paramref name="variableProvider"/> and returns the result.
/// </summary>
Expand All @@ -147,13 +172,27 @@ public object Evaluate(IVariableProvider variableProvider)
return this.Evaluate(new VariableProviderDictionary(variableProvider));
}

/// <summary>
/// Evaluates the supplied <paramref name="expression"/> using the supplied <paramref name="variableProvider"/> and returns the result.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="variableProvider"/> is null.</exception>
/// <exception cref="Exceptions.ExpressiveException">Thrown when there is a break in the evaluation process, check the InnerException for further information.</exception>
/// <param name="variableProvider">The <see cref="IVariableProvider"/> implementation to provide variable values during evaluation.</param>
/// <param name="expression">The expression to be evaluated.</param>
/// /// <returns>The result of the evaluation.</returns>
public object Evaluate(string expression, IVariableProvider variableProvider)
{
this.originalExpression = expression;
return Evaluate(variableProvider);
}

/// <summary>
/// Evaluates the expression using the supplied <paramref name="variableProvider"/> and returns the result.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="variableProvider"/> is null.</exception>
/// <exception cref="Exceptions.ExpressiveException">Thrown when there is a break in the evaluation process, check the InnerException for further information.</exception>
/// <param name="variableProvider">The <see cref="IVariableProvider"/> implementation to provide variable values during evaluation.</param>
/// <returns>The result of the evaluation.</returns>
/// /// <returns>The result of the evaluation.</returns>
public T Evaluate<T>(IVariableProvider variableProvider)
{
if (variableProvider is null)
Expand All @@ -175,6 +214,20 @@ public T Evaluate<T>(IVariableProvider variableProvider)
}
}

/// <summary>
/// Evaluates the supplied <paramref name="expression"/> using the supplied <paramref name="variableProvider"/> and returns the result.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="variableProvider"/> is null.</exception>
/// <exception cref="Exceptions.ExpressiveException">Thrown when there is a break in the evaluation process, check the InnerException for further information.</exception>
/// <param name="variableProvider">The <see cref="IVariableProvider"/> implementation to provide variable values during evaluation.</param>
/// <param name="expression">The expression to be evaluated.</param>
/// /// <returns>The result of the evaluation.</returns>
public T Evaluate<T>(string expression, IVariableProvider variableProvider)
{
this.originalExpression = expression;
return Evaluate<T>(variableProvider);
}

/// <summary>
/// Evaluates the expression using the supplied variables asynchronously and returns the result via the callback.
/// </summary>
Expand All @@ -186,6 +239,19 @@ public void EvaluateAsync(Action<string, object> callback, IDictionary<string, o
this.EvaluateAsync<object>(callback, variables);
}

/// <summary>
/// Evaluates the expression using the supplied variables asynchronously and returns the result via the callback.
/// </summary>
/// <exception cref="System.ArgumentNullException">Thrown if the callback is not supplied.</exception>
/// <param name="callback">Provides the result once the evaluation has completed.</param>
/// <param name="expression">The expression to be evaluated.</param>
/// <param name="variables">The variables to be used in the evaluation.</param>
public void EvaluateAsync(string expression, Action<string, object> callback, IDictionary<string, object> variables = null)
{
this.originalExpression = expression;
this.EvaluateAsync<object>(callback, variables);
}

/// <summary>
/// Evaluates the expression using the supplied variables asynchronously and returns the result via the callback.
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions Source/Expressive/Utils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Expressive.Utils
{
public static class Reflective
{
/// <summary>
/// Method to get a list of types implementing an interface
/// </summary>
/// <param name="interfaceType">Interface we want to know implementing classes.</param>
/// <returns></returns>
public static List<TypeInfo> GetClassesImplementingInterface(Type interfaceType)
{
Assembly asm = interfaceType.GetTypeInfo().Assembly; //thanks to @mjwills for his helpfull comment

return asm.DefinedTypes.Where(x => x.ImplementedInterfaces.Contains(interfaceType) && !x.IsAbstract).ToList();
}

/// <summary>
/// Getting a list of objects from a type info list
/// </summary>
/// <param name="typeInfos">List of types for which we want to create an instance.</param>
/// <returns>A list of instances of T type</returns>
/// <typeparam name="T">Interface type to return</typeparam>
public static List<T> GetInstances<T>(List<TypeInfo> typeInfos)
{
return typeInfos.Select(typeInfo => Activator.CreateInstance(typeInfo.AsType())).Cast<T>().ToList();
}
}
}