Skip to content

ramihamati/expressionparser

Repository files navigation

1. Evaluating an expression

ConverterManager converterManager = ConverterManager.Create(typeof(Convertibles));
FunctionProvider functionProvider = FunctionProvider.Create(converterManager, typeof(Functions), typeof(Functions2));
 
ParameterInt32 height = new ParameterInt32("height", 20);
ParameterDouble volume = new ParameterDouble("volume", 22);
ParameterInstance myRoom = new ParameterInstance("myRoom", new Room { Spatial = new Spatial { Area = 100.5, Perimeter = 22.5} });
ParameterCollection parameterCollection = new ParameterCollection(height, volume, myRoom);
ExpressionFabric expressionFabric = ExpressionFabric.Create(functionProvider, parameterCollection);
 
string expr1 = "myRoom.Spatial.Area + Sqrt(myRoom.Spatial.Perimeter) * (-1)";
string expr2 = "-Max(List(1,2,3,4,5,6, Max(List(10,22)) ))";
string expr3 = "Max(List(12,2, (1+2)))";
 
IExprModel model1 = expressionFabric.CreateModel(expr2);
 
switch (model1)
{
    case ExprModelInvalidComponent emiData:
      Console.WriteLine(emiData.ExprInvalidComponent.ErrorMessage);
        break;
    case ExprModelNotValidated emnData:
        Console.WriteLine("Corrected is " + emnData.CorrectedContext);
        Console.WriteLine(emnData.ValidationResult.Message);
        Console.WriteLine("Err : " + emnData.ValidationResult.ArgumentError);
        break;
    default:
        //here is the result
        EvaluateComponentResult<ExprComponent> result = model1.GetResult();
        if (!result.IsValid)
            Console.WriteLine(result.ErrorMessage);
        else
       {
             ParameterObject paramResult = ((ExprParameterComponent)result.ExprComponent).ParameterBase;
             Console.WriteLine(paramResult.GetValue());
                    }
        break;
 
}

2. Using a function

Our function has the following method implemented:

[Declared]
public static ParameterDouble Sqrt([MinValue(0)] ParameterDouble value)
{
    return new ParameterDouble(ParametersManager.NextName(), Math.Sqrt(value.GetValue()));
}

Define some parameters:

ParameterDouble data1 = new ParameterDouble("data1", -2);
ParameterDouble data2 = new ParameterDouble("data2", -12);
ParameterObject[] doubles = new ParameterObject[] {data1,data2};
ParameterDoubleArr doubleArr1 = new ParameterDoubleArr
("doubleList", doubles);

Creating the FunctionProvider:

ConverterManager converterManager1 = ConverterManager.Create(typeof(Convertible));
FunctionProvider fp = FunctionProvider.Create(converterManager1,typeof(Functions))

Getting the function:

FunctionBase sqrt = fp.GetByName("Max").Value;
var result1 = sqrt.Invoke(new ParameterObject[] { doubleArr1 });

Evaluating:

Console.WriteLine(result1.Errors);
Console.WriteLine(result1.Result.GetValue());

3. Parametters

**Hierarchy** All parameters (simple or array like) derive from the base object ParameterObject. The inheritance looks like: `IParameterObject` interface is the interface defining the starting point of parameter composition
public interface IParameterObject
    {
        string Name { get; }
        object GetValue();
    }

Interface IParameter defines the operations to be implemented by different types of parameters. It also acts as the base of strongly types parameters.

public interface IParameter<T> : IParameterObject where T: IParameter<T>
    {
        T Op_Add(T other);
        T Op_Minus(T other);
        T Op_Mult(T other);
        T Op_Div(T other);
        T Op_Mod(T other);
        T Op_Pow(T other);
    }

public abstract class ParameterObject : IParameterObject public abstract class Parameter : ParameterObject, IParameter<Parameter>

IParameterArray is inherited by array type parameters (ParameterDoubleArr, etc)

public interface IParameterArray<T> where T : ParameterObject
public abstract class ParameterBase<T> : Parameter

Collection The parameter collection can store any type of parameter (ParameterDouble, ParameterDoubleArr, etc).

3.1 ParameterDouble

Represents a class that stores a double value.

Syntax

public class ParameterDouble : ParameterBase<double>

Constructor

public ParameterDouble(string name, double value) : base(name, value)

Methods

Return the value of the parameter:

double GetValue()

Create a new parameter with a default name:

public static ParameterDouble Create(double value)

Properties

string Name { get; protected set; }

Example

ParameterDouble volume = new ParameterDouble("volume", 100);

3.2 ParameterInt32

Represents a class that stores an INT32 value.

Syntax

public class ParameterInt32 : ParameterBase<int>

Constructor

public ParameterInt32(string name, Int32 value) : base(name, value)

Methods

Return the value of the parameter:

Int32 GetValue()

Create a new parameter with a default name:

public static ParameterInt32 Create(Int32 value)

Properties

string Name { get; protected set; }

Example

ParameterInt32 volume = new ParameterInt32("volume", 100);

3.3 ParameterInt64

Represents a class that stores an INT64 value.

Syntax

public class ParameterInt64 : ParameterBase<Int64>

Constructor

public ParameterInt64(string name, double value) : base(name, value)

Methods

Return the value of the parameter:

Int64 GetValue()

Create a new parameter with a default name:

public static ParameterInt64 Create(Int64 value)

Properties

string Name { get; protected set; }

Example

ParameterInt64 volume = new ParameterInt64("volume", 100);

3.4 ParameterSingle

Represents a class that stores a float value.

Syntax

public class ParameterSingle : ParameterBase<Single>

Constructor

public ParameterSingle(string name, Single value) : base(name, value)

Methods

Return the value of the parameter:

Single GetValue()

Create a new parameter with a default name:

public static ParameterSingle Create(Single value)

Properties

string Name { get; protected set; }

Example

ParameterSingle volume = new ParameterSingle("volume", 100);

3.5 ParameterDoubleArr

Represents a class that stores a collection of double values

Syntax public class ParameterDoubleArr : ParameterObjectBase<double[]>, IParameterArray<ParameterDouble>

Constructor

public ParameterDoubleArr(string name, double[] value) : base(name)
public ParameterDoubleArr(string name, ParameterObject[] value) : base(name)

Methods Returns an array of ParameterDouble items

ParameterDouble[] GetObjects()

Returns an array of double items

double[] GetValue()

Properties

string Name { get; protected set; }

Example ParameterDouble data1 = new ParameterDouble("data1", -2);

ParameterDouble data2 = new ParameterDouble("data2", -12);
 ParameterObject[] doubles = new ParameterObject[] { data1, data2 };
 ParameterDoubleArr doubleArr1 = new ParameterDoubleArr(
                "doubleList", doubles)
ParameterDoubleArr doubleArr2 = new ParameterDoubleArr(
         "doubleList", new double[] { 1, 33 });

3.6 ParameterInt32Arr

Represents a class that stores a collection of Int32 values

Syntax

public class ParameterInt32Arr : ParameterObjectBase<Int32[]>, IParameterArray<ParameterInt32>

public ParameterInt32Arr(string name, Int32[] value) : base(name) public ParameterInt32Arr(string name, ParameterObject[] value) : base(name)

Methods

Returns an array of ParameterInt32 items

ParameterInt32Arr[] GetObjects()

Returns an array of double items

Int32[] GetValue()

Properties string Name { get; protected set; }

Example

ParameterInt32 data1 = new ParameterInt32("data1", -2);
ParameterInt32 data2 = new ParameterInt32("data2", -12);
ParameterObject[] integers = new ParameterObject[] { data1, data2 };
ParameterInt32Arr intArr1 = new ParameterInt32Arr(
                "intList", integers);

ParameterInt32Arr intArr2 = new ParameterInt32Arr("intList", new int[] { 1, 33 });

3.7 ParameterInt64Arr

Represents a class that stores a collection of Int64 values

Syntax public class ParameterInt64Arr : ParameterObjectBase<Int64[]>, IParameterArray<ParameterInt64>

Constructor

public ParameterInt64Arr(string name, Int64[] value) : base(name)
public ParameterInt64Arr(string name, ParameterObject[] value) : base(name)

Methods Returns an array of ParameterInt64 items

ParameterInt64Arr[] GetObjects()

Returns an array of Int64 items

Int64[] GetValue()

Properties

string Name { get; protected set; }

Example

ParameterInt64 data1 = new ParameterInt64("data1", -2);
 ParameterInt64 data2 = new ParameterInt64("data2", -12);
 ParameterObject[] integers = new ParameterObject[] { data1, data2 };
 ParameterInt64Arr intArr1 = new ParameterInt64Arr("intList", integers);
ParameterInt64Arr intArr2 = new ParameterInt64Arr(
         "intList", new Int64[] { 1, 33 });

3.8 ParameterSingleArr

Represents a class that stores a collection of float values

Syntax

public class ParameterSingleArr : ParameterObjectBase<Single[]>, IParameterArray<ParameterSingle>

Constructor

public ParameterSingleArr(string name, Single[] value) : base(name)
public ParameterSingleArr(string name, ParameterObject[] value) : base(name)

Methods

Returns an array of ParameterSingle items

ParameterSingleArr[] GetObjects()

Returns an array of float items

Single[] GetValue()

Properties

string Name { get; protected set; }

Example

ParameterSingle data1 = new ParameterSingle("data1", -2);
 ParameterSingle data2 = new ParameterSingle("data2", -12);
 ParameterObject[] singles = new ParameterObject[] { data1, data2 };
 ParameterSingleArr singleArray = new ParameterSingleArr(
                "singles", singles);
ParameterSingleArr singleArray = new ParameterSingleArr(
         "intList", new float[] { 1, 33 });

3.9 ParametersManager

Represents a static class with several functionalities

Syntax public static class ParametersManager

Methods Returns a new generated name for a parameter

static string NextName()

Properties

static string namePrefix

If DoubleBeforeSingle is true then the attempt is to make a double instead of a single. This provides more precision to your data. Default value is true

static bool DoubleBeforeSingle

Static Methods Trying to unbox a component and create a parameter component from it. If the object is int then a new instance of ParameterInt32 is created. Works for primary data and array types of primary data int, float, double, long, int[], float[], double[], long[])

public static Maybe<ParameterObject> TryGetComponent(object data, ExprOptions exprOptions)

Trying to get the parameter component out of a string

public static Maybe<ParameterObject> TryGetNumberComponent(string expression, ExprOptions exprOptions)

3.10 Add a new Operator

To add a new operator you have several steps to accomplish and for this I will present an added operator

  • In class ExprOptions
public List<char> AllowedOperators = "+-^*/%".ToList();
public char OperatorPlusSign = '+';
  • Enum OperatorType
public enum OperatorType
    {
        Plus,
        Minus,
        Multiply,
        Divide,
        Mod,
        Power
    }
  • Class ExprOperatorComponent
public static ExprComponent Create(char charOp, ExprOptions exprOptions)
        {
            if (exprOptions.HasOperatorFormat(charOp.ToString()))
            {
                switch (charOp)
                {
                    //then add operators
                    case '+':
                        return new ExprOperatorComponent("+", exprOptions, OperatorType.Plus);
                    case '-':
                        return new ExprOperatorComponent("-", exprOptions, OperatorType.Minus);
                    case '*':
                        return new ExprOperatorComponent("*", exprOptions, OperatorType.Multiply);
                    case '/':
                        return new ExprOperatorComponent("/", exprOptions, OperatorType.Divide);
                    case '%':
                        return new ExprOperatorComponent("%", exprOptions, OperatorType.Mod);
                    case '^':
                        return new  ExprOperatorComponent("^", exprOptions, OperatorType.Power);
                    default:
                        return new ExprInvalidComponent(charOp.ToString(), exprOptions, string.Format("{0} is not a valid operator", charOp));
                }
            }
            else
            {
                return new ExprInvalidComponent(charOp.ToString(), exprOptions, string.Format("{0} is not a valid operator", charOp));
            }
        }
  • Class ExprModel – define operator strategies
Dictionary<OperatorType, IOperation> opStrategies = new Dictionary<OperatorType, IOperation>()
            {
                { OperatorType.Plus, new Add() },
                { OperatorType.Minus, new Subtract() },
                { OperatorType.Divide, new Divide()},
                { OperatorType.Multiply, new Multiply()},
                { OperatorType.Mod, new Mod()},
                { OperatorType.Power, new Power()},
            };
  • In PrimaryOperations there is one class for each operation
public class Add : IOperation
    {
        public EvaluateComponentResult<ExprParameterComponent> 
            Result(ExprParameterComponent First, ExprParameterComponent Second)
        {
            return
                Utils.EvalAndOp(First, Second, null, (_first, _second) =>
                {
                    return _first.Op_Add(_second);
                });
        }
    }
  • The EvalAndOp method evaluates expressions and attempts to get appropiate parameters.** It also provides means to check parameters before the operation (needed for /0 division)
public static EvaluateComponentResult<ExprParameterComponent> EvalAndOp
                (ExprParameterComponent first,
                 ExprParameterComponent second,
                 Func<ParameterObject, ParameterObject, EvaluateComponentResult<ExprParameterComponent>> postCheck,
                 Func<Parameter, Parameter, Parameter> operation)

The ExprParameterComponent class derives from ExprComponent and it has the following properties:

public string Context { get; protected set; }
   public ExprOptions ExprOptions { get; set; }
   public ParameterObject ParameterBase { get; private set; }
  • The ParameterBase class provide abstract methods to implement these operations:
public abstract Parameter Op_Add(Parameter other);
public abstract Parameter Op_Minus(Parameter other);
public abstract Parameter Op_Mult(Parameter other);
public abstract Parameter Op_Div(Parameter other);
public abstract Parameter Op_Mod(Parameter other);
public abstract Parameter Op_Pow(Parameter other);
  • Each Parameter class overrides the above method but redirects action to a sepparate class that handles also overflow data
public override Parameter Op_Add(Parameter other)
        {
            switch (other)
            {
                case ParameterInt32 other32:
                    return OverflowAct.AddWithOverflow(this.Value, other32.GetValue());
                case ParameterInt64 other64:
                    return OverflowAct.AddWithOverflow(this.Value, other64.GetValue());
                case ParameterSingle otherSingle:
                    return OverflowAct.AddWithOverflow(this.Value, otherSingle.GetValue());
                case ParameterDouble otherDouble:
                    return OverflowAct.AddWithOverflow(this.Value, otherDouble.GetValue());
                default:
                    throw new Exception("Unreachable");
            }
        }
  • An example of the final operation in the overflow class:
public static class OverflowAct
    {
        //Additions of primary numerical values
        public static Parameter AddWithOverflow(Int32 first, Int32 second)
        {
            int resultInt = first + second;
            if (resultInt >= second && resultInt >= first)
                return ParameterInt32.Create(resultInt);
            long resultLong = (long)first + second;

            return ParameterInt64.Create(resultLong);
        }

        public static Parameter AddWithOverflow(Int32 first, Int64 second)
        {
            long resultLong = (long)first + second;

            return ParameterInt64.Create(resultLong);
        }
}

3.11 ParameterCollection

Syntax public class ParameterCollection

Constructor

public ParameterCollection()
 public ParameterCollection(params ParameterObject[] parameterObjects)

Properties

public string[] ParametersNames{get;}

Methods

public void Add(ParameterObject parameter)
public void Add(params ParameterObject[] parameters)
public Maybe<ParameterObject> TryGetParameter(string name)

Usage ParameterCollection is used for the creation of the expression model. All parameters used in an expression are passed in this collection for evaluation:

ParameterInt32 height = new ParameterInt32("height", 20);
 ParameterDouble volume = new ParameterDouble("volume", 22);
 ParameterInstance myRoom = new ParameterInstance("myRoom", new Room { Spatial = new Spatial { 
   Area = 100.5, Perimeter = 22.5} });

 ParameterCollection parameterCollection = new ParameterCollection(height, volume, myRoom);

 ExpressionFabric expressionFabric = ExpressionFabric.Create(functionProvider, parameterCollection);
 String expr12 = "height*volume*myRoom.Spatial.Area + Sqrt(myRoom.Spatial.Perimeter) * (-1)";
 IExprModel model1 = expressionFabric.CreateModel(expr2);

4. ExprCommon

This namespace provides multiple helper functions used in the parser and also some configuration options

ExprOptions

ExprOptions represents a configurator for the expression parser.

Constructor public ExprOptions()

Fields

public char OpenBracket = '(';
public char ClosedBracket = ')';
public List<char> AlternativeOpenBrackets = new List<char> { '{', '[' };
public List<char> AlternativeClosedBrackets = new List<char> { '}', ']' };

public List<char> AllowedNumbers = "0123456789".ToList();
public char AllowedNamePrefix = '_';
public List<char> AllowedLetters = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".ToList();
public List<char> AllowedOperators = "+-^*/%".ToList();
public List<char> AllowedBrackets;
public char DecimalSeparator = '.';
public char GroupSeparator = ',';

public List<char> AllAlphaNumeric;
public List<char> AllAllowedCharacters;
public List<char> AllNamingCharacters;
public List<char> AllNumberCharacters;
public List<char> AllCharactersInNamesAndNumbers;//similar to AllNaming + Punctuation
/// <summary>
/// For Singular operators tests
/// </summary>
public char OperatorMinusSign = '-';
public char OperatorPlusSign = '+';
public char OperatorMultiplySign = '*';
public char OperatorDivideSign = '-';
public char OperatorModSign = '%';
public char OperatorExpSign = '^';

Methods Determine if a string has a numeric format. Multiple dots are not ignored, they are determined and warned in a validation sequence

public bool ContainsNumbersAndPoint(string value)

Determines if a string has a numeric format.

public bool HasNumericFormat(string value)

Determines if a string has a valid naming format, it can start with an underscore or a letter and contain letters or numbers

public bool HasNameFormat(string value)

public bool HasOperatorFormat(string value)

Checks if a string has the shape ‘someFunction(…)’

public bool HasFunctionFormat(string value)

Convertibles

Convertibles is a static class that define cast-ing methods. It allows you to define conversion ways from one parameter type to another.

In the namespace RHAPPExpressionParser.ExprCommon.Wrapped you can find Convertibles class with some predefined methods but you can define also other methods / classes.

Methods must be static and marked with Convertible Attribute.

Syntax

Converting a ParameterInt32 to a ParameterDouble

[Convertible]
public static ParameterDouble Convert(ParameterInt32 value)
   {
      return new ParameterDouble(value.Name, value.GetValue());
   }

Why? When evaluating an expression with no parameters (or if you have multiple parameter types) the parser will determine the type of the parameter The following expression will result in the addition of an Int32 type with a Single type. Or if in the RHAPPExpressionParser.ExprParameter.Bases.ParameterManager you set DoubleBeforeSingle = true then the addition will be between Int32 and Double. In this case the program needs to know how to convert Int32 value

"10+1.2"

Usage

ConverterManager converterManager = ConverterManager.Create(typeof(Convertibles));
FunctionProvider functionProvider = FunctionProvider.Create(converterManager, typeof(Functions), typeof(Functions2));

ParameterInt32 height = new ParameterInt32("height", 20);
ParameterDouble volume = new ParameterDouble("volume", 22);
ParameterCollection parameterCollection = new ParameterCollection(height, volume);
ExpressionFabric expressionFabric = ExpressionFabric.Create(functionProvider, parameterCollection);

5. FunctionWrapper

FunctionWrapper namespace offers the infrastracture for mapping functions that are used in the expression string.

5.1 FunctionBase

FunctionBase is the base class that stores the function name, it’s functionality, the arguments required and the argument validation components

Syntax public class FunctionBase

Constructor The constructor is private and Create function is used to generate a new instance. Note:Do not create a new instance of the functions you are using, this is functionality is provided by class FunctionProvider.

public static FunctionBase Create(MethodInfo baseMethod, 
MethodInfo[] overloadMethods, ConverterManager converterManager)

Properties

public string Name { get; private set; }
public MethodInfo MethodInfo { get; private set; }
public Type OwnerType { get; private set; }
public FunctionDefinitionType FunctionDefinitionType { get; private set; }
public ArgumentInfo[] Parameters { get; private set; }
public FunctionBase[] Overloads { get; private set; }
public int ParametersCount;
private ConverterManager ConverterManager { get; set; }

Methods

RuntimeEvaluateStatus Invoke(ParameterObject[] inputData)

5.2 RuntimeEvaluateStatus

RuntimeEvaluateStatus is returned when a function is invoked in an expression.

public class RuntimeEvaluateStatus
{
    public RuntimeArgumentStatus RuntimeArgumentStatus { get; set; }
 
    public string Errors { get; set; }
 
    public ParameterObject Result { get; set; }
}
public enum RuntimeArgumentStatus
    {
        OK,
        ValuesNotValidated,
        NoMathingSignatureFound,
        NaN,
        RuntimeError,
        NullResult,
        UnableToCast
    }

5.3 Defining Functions

Predefined functions are store in `RHAPPExpressionParser.ExprCommon.WrappedFunctions.Functions.` You can follow this example to define other functions.

Declared Attribute There is 1 attribute that is needed when defining functions. The declared attribute which sets up which function is the base and which is overloaded. You can have 1 base function and multiple overloaded functions. Note: An error is thrown is there are overloaded functions but no base function detected.

public class DeclaredAttribute : Attribute
{
    public FunctionDefinitionType FunctionDefinitionType { get;set;}

    public DeclaredAttribute()
    {
        this.FunctionDefinitionType = FunctionDefinitionType.Base;
    }
}
public enum FunctionDefinitionType
{
    Base,
    Overload
}

Function Definition A function is defined in a static class and then passed to the FunctionProvider instance

[Declared]
public static ParameterDouble Sqrt([MinValue(0)] ParameterDouble value)
{
    return new ParameterDouble(ParametersManager.NextName(), Math.Sqrt(value.GetValue()));
}
       
[Declared(FunctionDefinitionType = FunctionDefinitionType.Overload)]
public static ParameterDouble Sqrt([MinValue(0)] ParameterInt32 value)
{
    return new ParameterDouble(ParametersManager.NextName(), Math.Sqrt(value.GetValue()));
}

Argument Validation Attribute These attributes are argument attributes and they must inherit interface IArgumentValid. The validity of values passed are checked before the function is invoked. If the argument is not valid an error message is sent. Predefined attributes are stored in RHAPPExpressionParser.FunctionWrapper.Attributes.

public interface IArgumentValid
    {
        bool IsValid(ParameterObject Context);
        string ErrorMessage { get; }
    }

Example of a predefined attribute:

public class MinValueAttribute : System.Attribute, IArgumentValid
{
    private double MinValue { get; set; }

    public MinValueAttribute(double minValue)
    {
        this.MinValue = minValue;
    }

    public string ErrorMessage =>
        string.Format("Value must be greater then {0}", this.MinValue);

    public bool IsValid(ParameterObject Context)
    {
        switch (Context)
        {
            case ParameterInt32 contextInt32:
                return contextInt32.GetValue() >= this.MinValue;
            case ParameterInt64 contextInt64:
                return contextInt64.GetValue() >= this.MinValue;
            case ParameterSingle contextSingle:
                return contextSingle.GetValue() >= this.MinValue;
            case ParameterDouble contextDouble:
                return contextDouble.GetValue() >= this.MinValue;
            default:
                return false;
        }
    }
}

5.4 Params

Params attribute let’s you define a function with variable number of arguments. Params attribute must be on the last argument of the function and that argument must be an array type inheriting IParameterArray interface (ParameterInt32Arr, ParameterDoubleArr, etc..)

Example

[Declared(FunctionDefinitionType = FunctionDefinitionType.Base)]
public static ParameterDouble Max([Params] ParameterDoubleArr data)
{
    double result = data.GetValue().ToList().Aggregate((a, b) => Math.Max(a, b));
 
    return new ParameterDouble(ParametersManager.NextName(), result);
}

Now you can use the function by providing double values. Or int values if you have a convertible defined between int and double (one predefined one is in the Convertibles class)

string myExpression = "Max(1,2,3,4.5,6,Max(10,22))";

5.5 FunctionProvider

FunctionProvider will handle determining base and overloaded functions that are to be mapped. It receives as input the class where you defined your functions and the converterManager.

Syntax

public class FunctionProvider

Properties

public FunctionBase[] FunctionsBase { get; private set; }
 
public ConverterManager ConverterManager { get; private set; }
 
public string[] FunctionNames { get; set; }

Creating a new instance public static FunctionProvider Create(ConverterManager converterManager, params Type[] ownerClasses)

Usage

ConverterManager converterManager = ConverterManager.Create(typeof(Convertibles));
FunctionProvider functionProvider = FunctionProvider.Create(converterManager, typeof(Functions), typeof(Functions2));
 
ParameterInt32 height = new ParameterInt32("height", 20);
ParameterDouble volume = new ParameterDouble("volume", 22);
 
ParameterCollection parameterCollection = new ParameterCollection(height, volume);
 
ExpressionFabric expressionFabric = ExpressionFabric.Create(functionProvider, parameterCollection);
 
String expr1 = "2147483600+1000";
String expr2 = "myRoom.Spatial.Area + Sqrt(myRoom.Spatial.Perimeter) * (-1)";
 
string expr3 = "-Max(List(1,2,3,4,5,6, Max(List(10,22)) ))";
string expr4= "Max(List(1,2,3)) + Sqrt(1)";
IExprModel model1 = expressionFabric.CreateModel(expr1);
IExprModel model2 = expressionFabric.CreateModel(expr2);
IExprModel model3 = expressionFabric.CreateModel(expr3);
IExprModel model4 = expressionFabric.CreateModel(expr4);

6. ExpressionComponentTree

ExpressionComponentTree offers the functionality to create a tree of dependent components starting from a string expression. All classes derive from ExprComponent.

The following expression: “1+b+max(c)” is split into the following components: Level1: -> ExprNumericComponent : 1 -> ExprOperatorComponent : + -> ExprParameterComponent : b -> ExprOperatorComponent : + -> ExprFunctionComponent : max / c

Level 2 : The function component contains an ExprComplexComponent with following list of components: -> -> ExprParameterComponent : c

6.1 ExprComponent

Syntax

public abstract class ExprComponent
{
    public string Context { get; protected set; }
    //public string EncodedContext { get; private set; }
 
    public ExprOptions ExprOptions { get; set; }
 
    public ExprComponent(string ExpressionString, ExprOptions exprOptions)
    {
        this.ExprOptions = exprOptions;
 
        this.Context = ExpressionString;
    }
}

6.2 ExprComplexComponent

ExprComplexComponent stores a collection of Children components that will be further evaluated. The general rule is that the Children components must be of the following pattern : NonOperatorComponent / ExprOperatorComponent / NonOperatorComponent/..

Syntax

public class ExprComplexComponent : ExprComponent

Properties

public List<ExprComponent> Children { get; private set; }

Create

public static ExprComponent Create(string context,
                                    ExprOptions exprOptions,
                                    FunctionProvider functionProvider,
                                    ParameterCollection parameterCollection)

6.3 ExprFunctionComponent

ExprFunctionComponent stores the FunctionBase representing the function to be invoked and the values passed as arguments.

Syntax

public class ExprFunctionComponent : ExprComponent

Properties

public FunctionBase FunctionBase { get; set; }

public List<ExprComplexComponent> Arguments { get; private set; }

Create

public static ExprComponent Create(string expression, ExprOptions exprOptions,
                                    FunctionBase functionBase,
                                    Func<string, ExprComponent> CreateComplexComponent)

6.4 ExprNumericComponent

ExprNumericComponent just stores the string that would represent the number. This number is then converted to a parameter using the Parameter Manager method TryGetNumberComponent.

Syntax public class ExprNumericComponent : ExprComponent

Create public static ExprComponent Create(string expression, ExprOptions exprOptions)

6.5 ExprOperatorComponent

Syntax public class ExprOperatorComponent : ExprComponent

Properties public OperatorType OperatorType { get; set; }

Create A string with length equals to 1

public static ExprComponent Create(string expression, ExprOptions exprOptions, OperatorType operatorType) public static ExprComponent Create(char charOp, ExprOptions exprOptions)

Operator Type

public enum OperatorType
    {
        Plus,
        Minus,
        Multiply,
        Divide,
        Mod,
        Power
    }

6.6 ExprParameterComponent

ExprParameterComponent stores the ParameterObject and if the object is an instance it also stores the BindingMap to that property.

For the myRoom object the BindingMap is “Spatial.Area”

ParameterInstance myRoom = new ParameterInstance("myRoom", new Room { Spatial = new Spatial { Area = 100.5, Perimeter = 22.5} });
String expr12 = "myRoom.Spatial.Area + Sqrt(myRoom.Spatial.Perimeter)";

Syntax public class ExprParameterComponent : ExprComponent

Properties

public ParameterObject ParameterBase { get; private set; }
public string MapToProperty { get; set; }
public bool IsEnumerable { get; protected set; }

Create

public static ExprComponent Create
            (ExprOptions exprOptions, ParameterObject parameterBase, string mapToProperty = "")

6.7 ExprInvalidComponent

Syntax public class ExprInvalidComponent : ExprComponent

Properties public string ErrorMessage { get; set; }

Constructor

public ExprInvalidComponent(string ExpressionString, ExprOptions exprOptions, string errorMessage="") 
            : base(ExpressionString, exprOptions)

7. ExprModel

The expression model comes in the worflow after the expression was validated and correcter (ExprValidateAndCorrect), after the functions have been defined (FunctionWrapper), after the parameters were collected (ExprParameter) and after the expression was decomposed intro ExprComponents.

This class handles the evaluation of each component and combining them into a final result

7.1 ExprModel

Syntax public class ExprModel : IExprModel

Properties

private FunctionProvider FunctionProvider { get; set; }
private ParameterCollection ParameterCollection { get; set; }
public ExprComponent ExprComponent { get; private set; }
public string Context { get; private set; }
public string CorrectedContext { get; private set; }
public ExprOptions ExprOptions { get; private set; }

Methods public EvaluateComponentResult<ExprComponent> GetResult()

EvaluateComponentResult

public class EvaluateComponentResult<T> where T: ExprComponent
    {
        public T ExprComponent { get; set; }

        public bool IsValid { get; set; }

        public string ErrorMessage { get; set; }
    }

7.2 ExprModelInvalidComponent

Syntax public class ExprModelInvalidComponent : IExprModel

Properties

public EvaluateComponentResult<ExprComponent> GetResult() => null;
public string Context { get; }
public string CorrectedContext { get; }
public ExprInvalidComponent ExprInvalidComponent { get; private set; }

7.3 ExprModelNotValidated

Syntax public class ExprModelNotValidated : IExprModel

Properties

public EvaluateComponentResult<ExprComponent> GetResult() => null;
public string Context { get; }
public string CorrectedContext { get; }
public ValidationResult ValidationResult { get; private set; }

8. ExpressionFabric

The ExpressionFabric creats the environment for creating the expression models. It receives the FunctionProvider and ParameterCollection as arguments.

Syntax

public class ExpressionFabric

Create

public static ExpressionFabric Create(FunctionProvider functionProvider,ParameterCollection parameterCollection)

Create a model

CreateModel will receive as input a string. The expression is then validated and corrected. If this process succeeds the expression is then decomposed into a tree and checked for invalid components. The return is a decomposed clean tree for final evaluation

public IExprModel CreateModel(string expressionString)

About

old implementation of an expression parser

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages